PluginProbe
UpStream: a Project Management Plugin for WordPress / trunk
UpStream: a Project Management Plugin for WordPress vtrunk
trunk 1.39.0 1.39.1 1.39.2 1.39.3 2.0.7 2.1.0
upstream / includes / frontend / up-table-functions.php

up-table-functions.php in UpStream: a Project Management Plugin for WordPress trunk, at includes/frontend/up-table-functions.php

1,302 lines 36.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handle table functions
4 *
5 * @package UpStream\Frontend
6 */
7
8 namespace UpStream\Frontend;
9
10 use UpStream\Exception;
11 use UpStream\Factory;
12 use UpStream\Milestones;
13 use UpStream_View;
14
15 /**
16 * Array To Attrs
17 *
18 * @param mixed $data Data.
19 */
20 function upstream_array_to_attrs( $data ) {
21 $attrs = array();
22
23 foreach ( $data as $attr_key => $attr_value ) {
24 printf( '%s="%s" ', esc_attr( $attr_key ), esc_attr( $attr_value ) );
25 }
26 }
27
28 /**
29 * Get Milestones Fields
30 *
31 * @param mixed $are_comments_enabled Are Comments Enabled.
32 */
33 function upstream_get_milestones_fields( $are_comments_enabled = null ) {
34 $schema = array(
35 'milestone' => array(
36 'type' => 'raw',
37 'isOrderable' => true,
38 'label' => upstream_milestone_label(),
39
40 ),
41 'assigned_to' => array(
42 'type' => 'user',
43 'isOrderable' => true,
44 'label' => __( 'Assigned To', 'upstream' ),
45 ),
46 'tasks' => array(
47 'type' => 'custom',
48 'label' => upstream_task_label_plural(),
49 'isEditable' => false,
50 'renderCallback' => function ( $column_name, $column_value, $column, $row, $row_type, $project_id ) {
51 $tasks_open_count = isset( $row['task_open'] ) ? (int) $row['task_open'] : 0;
52 $tasks_count = isset( $row['task_count'] ) ? (int) $row['task_count'] : 0;
53
54 return sprintf(
55 '%d %s / %d %s',
56 $tasks_open_count,
57 _x( 'Open', 'Open Tasks', 'upstream' ),
58 $tasks_count,
59 _x( 'Total', 'Total number of Tasks', 'upstream' )
60 );
61 },
62 ),
63 'progress' => array(
64 'type' => 'percentage',
65 'isOrderable' => true,
66 'label' => __( 'Progress', 'upstream' ),
67 'isEditable' => false,
68 ),
69 'start_date' => array(
70 'type' => 'date',
71 'isOrderable' => true,
72 'label' => __( 'Start Date', 'upstream' ),
73 ),
74 'end_date' => array(
75 'type' => 'date',
76 'isOrderable' => true,
77 'label' => __( 'End Date', 'upstream' ),
78 ),
79 'color' => array(
80 'type' => 'colorpicker',
81 'label' => __( 'Color', 'upstream' ),
82 'isHidden' => true,
83 ),
84 'notes' => array(
85 'type' => 'wysiwyg',
86 'label' => __( 'Notes', 'upstream' ),
87 'isHidden' => true,
88 ),
89 'comments' => array(
90 'type' => 'comments',
91 'label' => __( 'Comments' ),
92 'isHidden' => true,
93 'isEditable' => false,
94 ),
95 );
96
97 if ( ! upstream_disable_milestone_categories() ) {
98 $schema['categories'] = array(
99 'type' => 'taxonomies',
100 'isOrderable' => true,
101 'label' => upstream_milestone_category_label_plural(),
102 'renderCallback' => function ( $column_name, $column_value, $column, $row, $row_type, $project_id ) {
103 if ( empty( $column_value ) ) {
104 if ( ! is_array( $column_value ) ) {
105 $column_value = array( $column_value );
106 }
107
108 foreach ( $column_value as &$value ) {
109 $term = get_term( (int) $value );
110
111 if ( ! is_wp_error( $term ) ) {
112 $value = $term->name;
113 }
114 }
115
116 $column_value = implode( ',', $column_value );
117 } else {
118 $column_value = sprintf( '<i class="s-text-color-gray">%s</i>', __( 'none', 'upstream' ) );
119 }
120
121 return $column_value;
122 },
123 );
124 }
125
126 if ( null === $are_comments_enabled ) {
127 $are_comments_enabled = upstream_are_comments_enabled_on_milestones();
128 }
129
130 if ( ! $are_comments_enabled ) {
131 unset( $schema['comments'] );
132 }
133
134 return apply_filters( 'upstream:project.milestones.fields', $schema );
135 }
136
137 /**
138 * Get Tasks Fields
139 *
140 * @param array $statuses Statuses.
141 * @param array $milestones Milestones.
142 * @param mixed $are_milestones_enabled Are Milestones Enabled.
143 * @param mixed $are_comments_enabled Are Comments Enabled.
144 */
145 function upstream_get_tasks_fields( $statuses = array(), $milestones = array(), $are_milestones_enabled = null, $are_comments_enabled = null ) {
146 if ( null === $are_milestones_enabled ) {
147 $are_milestones_enabled = ! upstream_are_milestones_disabled() && ! upstream_disable_milestones();
148 }
149
150 $statuses = empty( $statuses ) ? upstream_get_tasks_statuses() : $statuses;
151 $options = array();
152
153 $schema = array(
154 'title' => array(
155 'type' => 'raw',
156 'isOrderable' => true,
157 'label' => __( 'Title', 'upstream' ),
158 ),
159 'assigned_to' => array(
160 'type' => 'user',
161 'isOrderable' => true,
162 'label' => __( 'Assigned To', 'upstream' ),
163 ),
164 'status' => array(
165 'type' => 'custom',
166 'label' => __( 'Status', 'upstream' ),
167 'isOrderable' => true,
168 'renderCallback' => function ( $column_name, $column_value, $column, $row, $row_type, $project_id ) use (
169 &
170 $statuses,
171 &$options
172 ) {
173 if ( strlen( $column_value ) > 0 ) {
174 if ( isset( $statuses[ $column_value ] ) ) {
175 $column_value = sprintf(
176 '<span class="badge up-o-label" style="background-color: %s;">%s</span>',
177 isset( $statuses[ $column_value ]['color'] ) ? esc_attr( $statuses[ $column_value ]['color'] ) : '',
178 esc_html( $statuses[ $column_value ]['name'] )
179 );
180 } else {
181 $column_value = sprintf(
182 '<span class="badge up-o-label" title="%s" style="background-color: %s;">%s <i class="fa fa-ban"></i></span>',
183 __( "This Status doesn't exist anymore.", 'upstream' ),
184 '#bdc3c7',
185 esc_html( $column_value )
186 );
187 }
188 } else {
189 $column_value = sprintf( '<i class="s-text-color-gray">%s</i>', __( 'none', 'upstream' ) );
190 }
191
192 return $column_value;
193 },
194 ),
195 'progress' => array(
196 'type' => 'percentage',
197 'isOrderable' => true,
198 'label' => __( 'Progress', 'upstream' ),
199 ),
200 'milestone' => array(
201 'type' => 'custom',
202 'isOrderable' => true,
203 'label' => upstream_milestone_label(),
204 'renderCallback' => function ( $column_name, $column_value, $column, $row, $row_type, $project_id ) {
205
206 if ( ! empty( $column_value ) ) {
207 try {
208 $milestone = Factory::get_milestone( $column_value );
209
210 $column_value = sprintf(
211 '<span class="badge up-o-label" style="background-color: %s;">%s</span>',
212 esc_attr( $milestone->getColor() ),
213 esc_html( $milestone->getName() )
214 );
215 } catch ( Exception $e ) {
216 $column_value = sprintf(
217 '<span class="badge up-o-label" title="%s" style="background-color: %s;">%s <i class="fa fa-ban"></i></span>',
218 __( "This Milestone doesn't exist anymore.", 'upstream' ),
219 '#bdc3c7',
220 esc_html( $column_value )
221 );
222 }
223 } else {
224 $column_value = sprintf( '<i class="s-text-color-gray">%s</i>', __( 'none', 'upstream' ) );
225 }
226
227 return $column_value;
228 },
229 ),
230 'start_date' => array(
231 'type' => 'date',
232 'isOrderable' => true,
233 'label' => __( 'Start Date', 'upstream' ),
234 ),
235 'end_date' => array(
236 'type' => 'date',
237 'isOrderable' => true,
238 'label' => __( 'End Date', 'upstream' ),
239 ),
240 'notes' => array(
241 'type' => 'wysiwyg',
242 'label' => __( 'Notes', 'upstream' ),
243 'isHidden' => true,
244 ),
245 'comments' => array(
246 'type' => 'comments',
247 'label' => __( 'Comments' ),
248 'isHidden' => true,
249 'isEditable' => false,
250 ),
251 );
252
253 if ( null === $are_comments_enabled ) {
254 $are_comments_enabled = upstream_are_comments_enabled_on_tasks();
255 }
256
257 if ( false === $are_milestones_enabled ) {
258 unset( $schema['milestone'] );
259 }
260
261 if ( ! $are_comments_enabled ) {
262 unset( $schema['comments'] );
263 }
264
265 return apply_filters( 'upstream:project.tasks.fields', $schema );
266 }
267
268 /**
269 * Get Bugs Fields
270 *
271 * @param array $severities Severities.
272 * @param array $statuses Statuses.
273 * @param mixed $are_comments_enabled Are Comments Enabled.
274 */
275 function upstream_get_bugs_fields( $severities = array(), $statuses = array(), $are_comments_enabled = null ) {
276 if ( empty( $severities ) ) {
277 $severities = upstream_get_bugs_severities();
278 }
279
280 if ( empty( $statuses ) ) {
281 $statuses = upstream_get_bugs_statuses();
282 }
283
284 $options = null;
285
286 $schema = array(
287 'title' => array(
288 'type' => 'raw',
289 'isOrderable' => true,
290 'label' => __( 'Title', 'upstream' ),
291 ),
292 'assigned_to' => array(
293 'type' => 'user',
294 'isOrderable' => true,
295 'label' => __( 'Assigned To', 'upstream' ),
296 ),
297 'severity' => array(
298 'type' => 'custom',
299 'label' => __( 'Severity', 'upstream' ),
300 'isOrderable' => true,
301 'renderCallback' => function ( $column_name, $column_value, $column, $row, $row_type, $project_id ) use (
302 &
303 $severities,
304 &$options
305 ) {
306 if ( strlen( $column_value ) > 0 ) {
307 if ( isset( $severities[ $column_value ] ) ) {
308 $column_value = sprintf(
309 '<span class="badge up-o-label" style="background-color: %s;">%s</span>',
310 esc_attr( $severities[ $column_value ]['color'] ),
311 esc_html( $severities[ $column_value ]['name'] )
312 );
313 } else {
314 $column_value = sprintf(
315 '<span class="badge up-o-label" title="%s" style="background-color: %s;">%s <i class="fa fa-ban"></i></span>',
316 __( "This Severity doesn't exist anymore.", 'upstream' ),
317 '#bdc3c7',
318 esc_html( $column_value )
319 );
320 }
321 } else {
322 $column_value = sprintf( '<i class="s-text-color-gray">%s</i>', __( 'none', 'upstream' ) );
323 }
324
325 return $column_value;
326 },
327 ),
328 'status' => array(
329 'type' => 'custom',
330 'label' => __( 'Status', 'upstream' ),
331 'isOrderable' => true,
332 'renderCallback' => function ( $column_name, $column_value, $column, $row, $row_type, $project_id ) use (
333 &
334 $statuses,
335 &$options
336 ) {
337 if ( strlen( $column_value ) > 0 ) {
338 if ( isset( $statuses[ $column_value ] ) ) {
339 $column_value = sprintf(
340 '<span class="badge up-o-label" style="background-color: %s;">%s</span>',
341 esc_attr( $statuses[ $column_value ]['color'] ),
342 esc_html( $statuses[ $column_value ]['name'] )
343 );
344 } else {
345 $column_value = sprintf(
346 '<span class="badge up-o-label" title="%s" style="background-color: %s;">%s <i class="fa fa-ban"></i></span>',
347 __( "This Status doesn't exist anymore.", 'upstream' ),
348 '#bdc3c7',
349 esc_html( $column_value )
350 );
351 }
352 } else {
353 $column_value = sprintf( '<i class="s-text-color-gray">%s</i>', __( 'none', 'upstream' ) );
354 }
355
356 return $column_value;
357 },
358 ),
359 'due_date' => array(
360 'type' => 'date',
361 'isOrderable' => true,
362 'label' => __( 'Due Date', 'upstream' ),
363 ),
364 'file' => array(
365 'type' => 'file',
366 'isOrderable' => false,
367 'label' => __( 'File', 'upstream' ),
368 ),
369 'description' => array(
370 'type' => 'wysiwyg',
371 'label' => __( 'Description', 'upstream' ),
372 'isHidden' => true,
373 ),
374 'comments' => array(
375 'type' => 'comments',
376 'label' => __( 'Comments' ),
377 'isHidden' => true,
378 'isEditable' => false,
379 ),
380 );
381
382 if ( null === $are_comments_enabled ) {
383 $are_comments_enabled = upstream_are_comments_enabled_on_bugs();
384 }
385
386 if ( ! $are_comments_enabled ) {
387 unset( $schema['comments'] );
388 }
389
390 return apply_filters( 'upstream:project.bugs.fields', $schema );
391 }
392
393 /**
394 * Get Files Fields
395 *
396 * @param mixed $are_comments_enabled Are Comments Enabled.
397 */
398 function upstream_get_files_fields( $are_comments_enabled = null ) {
399 $schema = array(
400 'title' => array(
401 'type' => 'raw',
402 'isOrderable' => true,
403 'label' => __( 'Title', 'upstream' ),
404 ),
405 'created_by' => array(
406 'type' => 'user',
407 'isOrderable' => true,
408 'label' => __( 'Uploaded by', 'upstream' ),
409 'isEditable' => false,
410 ),
411 'created_at' => array(
412 'type' => 'date',
413 'isOrderable' => true,
414 'label' => __( 'Upload Date', 'upstream' ),
415 'isEditable' => false,
416 ),
417 'assigned_to' => array(
418 'type' => 'user',
419 'isOrderable' => false,
420 'label' => __( 'Assigned To', 'upstream' ),
421 ),
422 'file' => array(
423 'type' => 'file',
424 'isOrderable' => false,
425 'label' => __( 'File', 'upstream' ),
426 ),
427 'description' => array(
428 'type' => 'wysiwyg',
429 'label' => __( 'Description', 'upstream' ),
430 'isHidden' => true,
431 ),
432 'comments' => array(
433 'type' => 'comments',
434 'label' => __( 'Comments' ),
435 'isHidden' => true,
436 'isEditable' => false,
437 ),
438 );
439
440 if ( null === $are_comments_enabled ) {
441 $are_comments_enabled = upstream_are_comments_enabled_on_files();
442 }
443
444 if ( ! $are_comments_enabled ) {
445 unset( $schema['comments'] );
446 }
447
448 return apply_filters( 'upstream:project.files.fields', $schema );
449 }
450
451 /**
452 * Get Project Fields
453 *
454 * @param array $statuses Statuses.
455 */
456 function upstream_get_project_fields( $statuses = array() ) {
457 if ( empty( $statuses ) ) {
458 $statuses = upstream_get_all_project_statuses();
459 }
460
461 $options = null;
462
463 $schema = array(
464 'title' => array(
465 'type' => 'raw',
466 'isOrderable' => true,
467 'label' => __( 'Title', 'upstream' ),
468 ),
469 'status' => array(
470 'type' => 'custom',
471 'label' => __( 'Status', 'upstream' ),
472 'isOrderable' => true,
473 'renderCallback' => function ( $column_name, $column_value, $column, $row, $row_type, $project_id ) use (
474 &
475 $statuses,
476 &$options
477 ) {
478 if ( strlen( $column_value ) > 0 ) {
479 if ( isset( $statuses[ $column_value ] ) ) {
480 $column_value = sprintf(
481 '<span class="badge up-o-label" style="background-color: %s;">%s</span>',
482 esc_attr( $statuses[ $column_value ]['color'] ),
483 esc_html( $statuses[ $column_value ]['name'] )
484 );
485 } else {
486 $column_value = sprintf(
487 '<span class="badge up-o-label" title="%s" style="background-color: %s;">%s <i class="fa fa-ban"></i></span>',
488 __( "This Status doesn't exist anymore.", 'upstream' ),
489 '#bdc3c7',
490 esc_html( $column_value )
491 );
492 }
493 } else {
494 $column_value = sprintf( '<i class="s-text-color-gray">%s</i>', __( 'none', 'upstream' ) );
495 }
496
497 return $column_value;
498 },
499 ),
500 'owner' => array(
501 'type' => 'user',
502 'isOrderable' => true,
503 'label' => __( 'Owner', 'upstream' ),
504 ),
505 'client' => array(
506 'type' => 'custom',
507 'isOrderable' => true,
508 'label' => upstream_client_label(),
509 ),
510 'client_users' => array(
511 'type' => 'array',
512 'label' => __( 'Client users', 'upstream' ),
513 'isOrderable' => true,
514 'renderCallback' => function ( $column_name, $column_value, $column, $row, $row_type, $project_id ) use (
515 &
516 $statuses,
517 &$options
518 ) {
519 if ( strlen( $column_value ) > 0 ) {
520 if ( isset( $statuses[ $column_value ] ) ) {
521 $column_value = sprintf(
522 '<span class="badge up-o-label" style="background-color: %s;">%s</span>',
523 esc_attr( $statuses[ $column_value ]['color'] ),
524 esc_html( $statuses[ $column_value ]['name'] )
525 );
526 } else {
527 $column_value = sprintf(
528 '<span class="badge up-o-label" title="%s" style="background-color: %s;">%s <i class="fa fa-ban"></i></span>',
529 __( "This Status doesn't exist anymore.", 'upstream' ),
530 '#bdc3c7',
531 esc_html( $column_value )
532 );
533 }
534 } else {
535 $column_value = sprintf( '<i class="s-text-color-gray">%s</i>', __( 'none', 'upstream' ) );
536 }
537
538 return $column_value;
539 },
540 ),
541 'start' => array(
542 'type' => 'date',
543 'isOrderable' => true,
544 'label' => __( 'Start', 'upstream' ),
545 ),
546 'end' => array(
547 'type' => 'date',
548 'isOrderable' => true,
549 'label' => __( 'End', 'upstream' ),
550 ),
551
552 'description' => array(
553 'type' => 'wysiwyg',
554 'label' => __( 'Description', 'upstream' ),
555 'isHidden' => true,
556 ),
557 );
558
559 return apply_filters( 'upstream:project.fields', $schema );
560 }
561
562 /**
563 * Render Table Header Column
564 *
565 * @param mixed $identifier Identifier.
566 * @param mixed $data Data.
567 * @return void
568 */
569 function upstream_render_table_header_column( $identifier, $data ) {
570 $attrs = array(
571 'data-column' => $identifier,
572 'class' => isset( $data['class'] ) ? ( is_array( $data['class'] ) ? implode(
573 ' ',
574 $data['class']
575 ) : $data['class'] ) : '',
576 );
577
578 $is_hidden = isset( $data['isHidden'] ) && (bool) $data['isHidden'];
579 if ( $is_hidden ) {
580 return;
581 }
582
583 $is_orderable = isset( $data['isOrderable'] ) && (bool) $data['isOrderable'];
584 if ( $is_orderable ) {
585 $attrs['class'] .= ' is-clickable is-orderable';
586 $attrs['role'] = 'button';
587 $attrs['scope'] = 'col';
588 } ?>
589 <th <?php upstream_array_to_attrs( $attrs ); ?>>
590 <?php echo isset( $data['label'] ) ? esc_html( $data['label'] ) : ''; ?>
591 <?php if ( $is_orderable ) : ?>
592 <span class="pull-right o-order-direction">
593 <i class="fa fa-sort"></i>
594 </span>
595 <?php endif; ?>
596 </th>
597 <?php
598 }
599
600 /**
601 * Render Table Header
602 *
603 * @param array $columns Columns.
604 * @param mixed $item_type Item Type.
605 * @return void
606 */
607 function upstream_render_table_header( $columns = array(), $item_type = null ) {
608 if ( is_null( $item_type ) ) {
609 return;
610 }
611
612 ?>
613 <thead>
614 <?php if ( ! empty( $columns ) ) : ?>
615 <tr scope="row">
616 <?php
617 foreach ( $columns as $column_identifier => $column ) {
618 upstream_render_table_header_column( $column_identifier, $column );
619 }
620 ?>
621
622 <?php do_action( 'upstream_table_columns_header', array( 'type' => $item_type ), $columns ); ?>
623 </tr>
624 <?php endif; ?>
625 </thead>
626 <?php
627 }
628
629 /**
630 * Render Table Column Value
631 *
632 * @param mixed $column_name Column Name.
633 * @param mixed $column_value Column Value.
634 * @param mixed $column Column.
635 * @param mixed $row Row.
636 * @param mixed $row_type Row Type.
637 * @param mixed $project_id Project Id.
638 * @return void
639 */
640 function upstream_render_table_column_value( $column_name, $column_value, $column, $row, $row_type, $project_id ) {
641 $is_hidden = isset( $column['isHidden'] ) && true === (bool) $column['isHidden'];
642
643 $viewable = upstream_override_access_field( true, $row_type, $row['id'], UPSTREAM_ITEM_TYPE_PROJECT, $project_id, $column_name, UPSTREAM_PERMISSIONS_ACTION_VIEW );
644
645 if ( $viewable ) {
646
647 $html = sprintf( '<i class="s-text-color-gray">%s</i>', esc_html__( 'none', 'upstream' ) );
648 $column_type = isset( $column['type'] ) ? $column['type'] : 'raw';
649
650 // Detect color values.
651 if ( 'raw' === $column_type && preg_match( '/^(#[0-9a-f]+|rgba?\()/i', $column_value ) ) {
652 $column_type = 'colorpicker';
653 }
654
655 if ( 'user' === $column_type ) {
656 if ( ! is_array( $column_value ) ) {
657 $column_value = (array) $column_value;
658 }
659
660 $names = upstream_get_users_display_name( $column_value );
661
662 // RSD: for some reason upstream_get_users_display_name returns 0 when there's nothign to show
663 // this fixes the display.
664 $html = ( '0' !== $names ) ? $names : $html;
665 } elseif ( 'taxonomies' === $column_type ) {
666 if ( ! is_array( $column_value ) ) {
667 $column_value = (array) $column_value;
668 }
669
670 $html = '';
671
672 if ( ! empty( $column_value ) ) {
673 $names = array();
674
675 foreach ( $column_value as $value ) {
676 if ( is_numeric( $value ) ) {
677 $term = get_term( (int) $value );
678
679 $names[] = $term->name;
680 } else {
681 $names[] = $value;
682 }
683 }
684
685 $html = esc_html( implode( ', ', $names ) );
686 }
687 } elseif ( 'percentage' === $column_type ) {
688 $html = esc_html( sprintf( '%d%%', (int) $column_value ) );
689 } elseif ( 'date' === $column_type ) {
690
691 if ( isset( $row[ $column_name . '.YMD' ] ) && $row[ $column_name . '.YMD' ] ) {
692 $ts = date_create_from_format( 'Y-m-d', $row[ $column_name . '.YMD' ] )->getTimestamp();
693 $html = esc_html( date_i18n( get_option( 'date_format' ), $ts ) );
694
695 } else {
696 $column_value = (int) $column_value;
697
698 if ( $column_value > 0 ) {
699 // RSD: timezone offset is here to ensure compatibility with previous wrong data
700 // TODO: should remove offset at some point.
701 $html = esc_html( upstream_format_date( $column_value + UpStream_View::get_time_zone_offset() ) );
702 }
703
704 $offset = get_option( 'gmt_offset' );
705 }
706 } elseif ( 'wysiwyg' === $column_type ) {
707 // replace newlines if not HTML.
708 if ( ! stristr( $column_value, '&lt;' ) ) {
709 $column_value = preg_replace( '/(?!>[\s]*).\r?\n(?![\s]*<)/', '$0<br />', trim( (string) $column_value ) );
710 }
711 if ( strlen( $column_value ) > 0 ) {
712 $html = upstream_esc_w( sprintf( '<blockquote>%s</blockquote>', html_entity_decode( $column_value ) ) );
713 } else {
714 $html = '<br>' . $html;
715 }
716 } elseif ( 'comments' === $column_type ) {
717 $html = upstream_render_comments_box( $row['id'], $row_type, $project_id, false, true );
718 } elseif ( 'custom' === $column_type ) {
719 if ( isset( $column['renderCallback'] ) && is_callable( $column['renderCallback'] ) ) {
720 $html = call_user_func(
721 $column['renderCallback'],
722 $column_name,
723 $column_value,
724 $column,
725 $row,
726 $row_type,
727 $project_id
728 );
729 }
730 } elseif ( 'file' === $column_type ) {
731
732 if ( is_array( $column_value ) && count( $column_value ) > 0 ) {
733 $column_value = $column_value[0];
734 }
735
736 if ( strlen( $column_value ) > 0 ) {
737 if ( upstream_filesytem_enabled() ) {
738 $file = upstream_upfs_info( $column_value );
739 if ( $file ) {
740 $html = sprintf(
741 '<a href="%s" target="_blank">%s</a>',
742 esc_url( upstream_upfs_get_file_url( $column_value ) ),
743 esc_html( $file->orig_filename )
744 );
745 }
746 } else {
747 if ( stristr( $column_value, '_upfs_' ) ) {
748 $column_value = '';
749 }
750
751 if ( @is_array( getimagesize( $column_value ) ) ) {
752 $html = sprintf(
753 '<a href="%s" target="_blank">
754 <img class="avatar itemfile" width="32" height="32" src="%1$s">
755 </a>',
756 esc_url( $column_value )
757 );
758 } else {
759 $html = sprintf(
760 '<a href="%s" target="_blank">%s</a>',
761 esc_url( $column_value ),
762 esc_html( basename( $column_value ) )
763 );
764 }
765 }
766 } elseif ( $is_hidden ) {
767 $html = '<br>' . $html;
768 }
769 } elseif ( 'array' === $column_type ) {
770 $column_value = array_filter( (array) $column_value );
771
772 if ( isset( $column['options'] ) ) {
773 $values = array();
774
775 if ( is_array( $column['options'] ) ) {
776 foreach ( $column_value as $value ) {
777 if ( isset( $column['options'][ $value ] ) ) {
778 $values[] = $column['options'][ $value ];
779 }
780 }
781 }
782
783 $values = implode( ', ', $values );
784 } elseif ( ! empty( $column_value ) ) {
785 $values = implode( ', ', $column_value );
786 }
787
788 if ( ! empty( $values ) ) {
789 if ( $is_hidden ) {
790 $html = '<br><span data-value="' . esc_attr( implode( ',', $column_value ) ) . '">' . esc_html( $values ) . '</span>';
791 } else {
792 $html = '<br><span>' . esc_html( implode( ',', $column_value ) ) . '</span>';
793 }
794 } else {
795 $html = '<br>' . $html;
796 }
797 } elseif ( 'colorpicker' === $column_type ) {
798 $column_value = trim( (string) $column_value );
799 if ( strlen( $column_value ) > 0 ) {
800 $html = '<br><div class="up-c-color-square has-tooltip" data-toggle="tooltip" title="' . esc_attr( $column_value ) . '">';
801 $html .= '<div style="background-color: ' . esc_attr( $column_value ) . '"></div>';
802 $html .= '</div>';
803 }
804
805 if ( $is_hidden ) {
806 $html = '<span data-value="' . esc_attr( $column_value ) . '">' . $html . '</span>';
807 }
808 } elseif ( 'radio' === $column_type ) {
809 if ( is_array( $column_value ) ) {
810 $column_value = $column_value[0];
811 }
812
813 $column_value = trim( (string) $column_value );
814
815 if ( strlen( $column_value ) > 0 ) {
816 if ( '__none__' === $column_value ) {
817 $html = '<i class="s-text-color-gray">' . esc_html__( 'none', 'upstream' ) . '</i>';
818 } else {
819 $html = esc_html( $column_value );
820 }
821 }
822
823 $html = '<br>' . $html;
824
825 if ( $is_hidden ) {
826 $html = '<span data-value="' . esc_attr( $column_value ) . '">' . $html . '</span>';
827 }
828 } else {
829 if ( is_array( $column_value ) ) {
830 if ( isset( $column_value[0] ) ) {
831 $column_value = $column_value[0];
832 } else {
833 $column_value = '';
834 }
835 }
836
837 $column_value = trim( (string) $column_value );
838 if ( strlen( $column_value ) > 0 ) {
839 $html = esc_html( $column_value );
840 }
841
842 if ( $is_hidden ) {
843 $html = '<span data-value="' . esc_attr( $column_value ) . '">' . $html . '</span>';
844 }
845 }
846 } else {
847 $html = '<span class="badge up-o-label" style="background-color:#666;color:#fff">(hidden)</span>';
848 }
849
850 $html = apply_filters(
851 'upstream:frontend:project.table.body.td_value',
852 $html,
853 $column_name,
854 $column_value,
855 $column,
856 $row,
857 $row_type,
858 $project_id
859 );
860
861 echo wp_kses_post( $html );
862 }
863
864 /**
865 * Render Table Body
866 *
867 * @param mixed $data Data.
868 * @param mixed $visible_columns_schema Visible Columns Schema.
869 * @param mixed $hidden_columns_schema Hidden Columns Schema.
870 * @param mixed $row_type Row Type.
871 * @param mixed $project_id Project Id.
872 * @param mixed $table_settings Table Settings.
873 * @return void
874 */
875 function render_table_body( $data, $visible_columns_schema, $hidden_columns_schema, $row_type, $project_id, $table_settings = array() ) {
876 $visible_columns_schema_count = count( $visible_columns_schema );
877
878 ?>
879 <tbody>
880 <?php
881 if ( count( $data ) > 0 ) :
882 $is_row_index_odd = true;
883 ?>
884 <?php
885 foreach ( $data as $id => $row ) :
886 $row_attrs = array(
887 'class' => 'is-filtered t-row-' . ( $is_row_index_odd ? 'odd' : 'even' ),
888 'data-id' => $id,
889 );
890
891 if ( ! empty( $hidden_columns_schema ) ) {
892 $row_attrs['class'] .= ' is-expandable';
893 $row_attrs['aria-expanded'] = 'false';
894 }
895
896 $is_first = true;
897 ?>
898 <tr <?php upstream_array_to_attrs( $row_attrs ); ?>>
899 <?php
900 foreach ( $visible_columns_schema as $column_name => $column ) :
901 $column_value = isset( $row[ $column_name ] ) ? $row[ $column_name ] : null;
902
903 if ( in_array( $column['type'], array( 'user', 'array' ), true ) ) {
904 if ( ! is_array( $column_value ) ) {
905 $column_value = array( (int) $column_value );
906 }
907 }
908
909 if ( 'taxonomies' === $column['type'] && is_array( $column_value ) ) {
910 $column_value = Milestones::getInstance()->get_categories_names( $column_value );
911 }
912
913 $column_attrs = array(
914 'data-column' => $column_name,
915 'data-value' => is_array( $column_value ) ? implode( ', ', $column_value ) : $column_value,
916 'data-type' => $column['type'],
917 );
918
919 // Check if we have an specific value in the column, for ordering.
920 $column_attrs['data-order'] = $column_attrs['data-value'];
921 if ( isset( $row[ $column_name . '_order' ] ) ) {
922 $column_attrs['data-order'] = $row[ $column_name . '_order' ];
923 }
924
925 $viewable = upstream_override_access_field( true, $row_type, $row['id'], UPSTREAM_ITEM_TYPE_PROJECT, $project_id, $column_name, UPSTREAM_PERMISSIONS_ACTION_VIEW );
926 if ( ! $viewable ) {
927 $column_attrs['data-value'] = '0';
928 $column_attrs['data-order'] = '(hidden)';
929 }
930
931 if ( $is_first ) {
932 $column_attrs['class'] = 'is-clickable';
933 $column_attrs['role'] = 'button';
934 }
935 ?>
936 <td <?php upstream_array_to_attrs( $column_attrs ); ?>>
937 <?php if ( $is_first ) : ?>
938 <i class="fa fa-angle-right"></i>&nbsp;
939 <?php endif; ?>
940
941 <?php upstream_render_table_column_value( $column_name, $column_value, $column, $row, $row_type, $project_id ); ?>
942 </td>
943
944
945 <?php $is_first = false; ?>
946 <?php endforeach; ?>
947
948 <?php do_action( 'upstream_table_columns_data', $table_settings, $visible_columns_schema, $project_id, $row ); ?>
949 </tr>
950
951 <?php if ( ! empty( $hidden_columns_schema ) ) : ?>
952 <tr data-parent="<?php echo esc_attr( $id ); ?>" aria-expanded="false" style="display: none;">
953 <td colspan="<?php echo esc_attr( $visible_columns_schema_count ); ?>">
954 <div>
955 <?php
956 foreach ( $hidden_columns_schema as $column_name => $column ) :
957 $column_value = isset( $row[ $column_name ] ) ? $row[ $column_name ] : null;
958 ?>
959 <div class="form-group" data-column="<?php echo esc_attr( $column_name ); ?>">
960 <label><?php echo isset( $column['label'] ) ? esc_html( $column['label'] ) : ''; ?></label>
961 <?php
962 upstream_render_table_column_value(
963 $column_name,
964 $column_value,
965 $column,
966 $row,
967 $row_type,
968 $project_id
969 );
970 ?>
971 </div>
972 <?php endforeach; ?>
973 </div>
974 </td>
975 </tr>
976 <?php
977 endif;
978 $is_row_index_odd = ! $is_row_index_odd;
979 ?>
980 <?php endforeach; ?>
981 <?php else : ?>
982 <tr data-empty>
983 <td colspan="<?php echo esc_attr( $visible_columns_schema_count ); ?>">
984 <?php esc_html_e( 'No results found.', 'upstream' ); ?>
985 </td>
986 </tr>
987 <?php endif; ?>
988 </tbody>
989 <?php
990 }
991
992 /**
993 * Render Table
994 *
995 * @param array $table_attrs Table Attrs.
996 * @param array $columns_schema Columns Schema.
997 * @param array $data Data.
998 * @param string $item_type Item Type.
999 * @param int $project_id Project Id.
1000 * @return void
1001 */
1002 function upstream_render_table( $table_attrs = array(), $columns_schema = array(), $data = array(), $item_type = '', $project_id = 0 ) {
1003 $table_attrs['class'] = array_filter(
1004 isset( $table_attrs['class'] ) ? ( ! is_array( $table_attrs['class'] ) ? explode(
1005 ' ',
1006 $table_attrs['class']
1007 ) : (array) $table_attrs['class'] ) : array()
1008 );
1009 $table_attrs['class'] = array_unique(
1010 array_merge(
1011 $table_attrs['class'],
1012 array(
1013 'o-data-table',
1014 'table',
1015 'table-bordered',
1016 'table-responsive',
1017 'table-hover',
1018 'is-orderable',
1019 )
1020 )
1021 );
1022
1023 $table_attrs['cellspacing'] = 0;
1024 $table_attrs['width'] = '100%';
1025
1026 $visible_columns_schema = array();
1027 $hidden_columns_schema = array();
1028
1029 foreach ( $columns_schema as $column_name => $column_args ) {
1030 if ( isset( $column_args['isHidden'] ) && true === (bool) $column_args['isHidden'] ) {
1031 $hidden_columns_schema[ $column_name ] = $column_args;
1032 } else {
1033 $visible_columns_schema[ $column_name ] = $column_args;
1034 }
1035 }
1036
1037 // Get the table ordering, if set.
1038 $table_id = array_key_exists( 'id', $table_attrs ) ? $table_attrs['id'] : '';
1039
1040 if ( ! empty( $table_id ) ) {
1041 $ordering = upstream_get_table_order( $table_id );
1042
1043 if ( ! empty( $ordering ) ) {
1044 $table_attrs['data-ordered-by'] = $ordering['column'];
1045 $table_attrs['data-order-dir'] = $ordering['orderDir'];
1046 }
1047 }
1048
1049 $table_attrs['class'] = implode( ' ', $table_attrs['class'] );
1050 ?>
1051 <table <?php upstream_array_to_attrs( $table_attrs ); ?>>
1052 <?php upstream_render_table_header( $visible_columns_schema, $item_type ); ?>
1053 <?php
1054 render_table_body(
1055 $data,
1056 $visible_columns_schema,
1057 $hidden_columns_schema,
1058 $item_type,
1059 $project_id,
1060 $table_attrs
1061 );
1062 ?>
1063 </table>
1064 <?php
1065 $opt_arr = array(
1066 'milestone' => upstream_milestone_label_plural(),
1067 'task' => upstream_task_label_plural(),
1068 'bug' => upstream_bug_label_plural(),
1069 'file' => upstream_file_label_plural(),
1070 );
1071 $count_value = count( $data ) > 0 ? count( $data ) : '';
1072 echo "<span class='sub_count p_count' id='" . esc_attr( $item_type ) . "_count'>" . esc_html( $count_value ) . '</span>';
1073 ?>
1074 <span class="p_count">
1075 <?php
1076 if ( count( $data ) > 0 ) {
1077 echo esc_html(
1078 sprintf(
1079 // translators: %s: Item name.
1080 __( ' %s found', 'upstream' ),
1081 $opt_arr[ $item_type ]
1082 )
1083 );
1084 }
1085 ?>
1086 </span>
1087 <?php
1088 }
1089
1090 /**
1091 * Render Table Filter
1092 *
1093 * @param mixed $filter_type Filter Type.
1094 * @param mixed $column_name Column Name.
1095 * @param mixed $args Args.
1096 * @param mixed $render_form_group Render Form Group.
1097 */
1098 function upstream_render_table_filter( $filter_type, $column_name, $args = array(), $render_form_group = true ) {
1099 if ( ! in_array( $filter_type, array( 'search', 'select' ), true )
1100 || empty( $column_name )
1101 ) {
1102 return false;
1103 }
1104
1105 $render_form_group = (bool) $render_form_group;
1106
1107 $is_hidden = ! isset( $args['hidden'] ) || ( isset( $args['hidden'] ) && true === (bool) $args['hidden'] );
1108
1109 if ( $render_form_group ) {
1110 echo '<div class="form-group">';
1111 }
1112
1113 if ( 'search' === $filter_type ) {
1114 $input_attrs = array(
1115 'type' => 'search',
1116 'class' => 'form-control',
1117 'data-column' => $column_name,
1118 'data-compare-operator' => isset( $args['operator'] ) ? $args['operator'] : 'contains',
1119 );
1120
1121 if ( isset( $args['attrs'] ) && ! empty( $args['attrs'] ) ) {
1122 $input_attrs = array_merge( $args['attrs'], $input_attrs );
1123 }
1124 ?>
1125 <div class="input-group">
1126 <div class="input-group-text">
1127 <i class="fa fa-search"></i>
1128 </div>
1129 <input <?php upstream_array_to_attrs( $input_attrs ); ?>>
1130 </div>
1131 <?php
1132 } elseif ( 'select' === $filter_type ) {
1133 $input_attrs = array(
1134 'class' => 'form-control o-select2',
1135 'data-column' => $column_name,
1136 'multiple' => 'multiple',
1137 'data-compare-operator' => isset( $args['operator'] ) ? $args['operator'] : 'contains',
1138 );
1139
1140 if ( isset( $args['attrs'] ) && ! empty( $args['attrs'] ) ) {
1141 $input_attrs = array_merge( $args['attrs'], $input_attrs );
1142 }
1143
1144 $has_icon = isset( $args['icon'] ) && ! empty( $args['icon'] );
1145 if ( $has_icon ) :
1146 ?>
1147 <div class="input-group">
1148 <div class="input-group-text">
1149 <i class="fa fa-filter"></i>
1150 </div>
1151 <?php endif; ?>
1152
1153 <select <?php upstream_array_to_attrs( $input_attrs ); ?>>
1154 <option value></option>
1155 <option value="__none__"><?php esc_html_e( 'None', 'upstream' ); ?></option>
1156 <?php
1157 if ( isset( $args['options'] ) && is_array( $args['options'] ) && count( $args['options'] ) ) :
1158 ?>
1159 <?php foreach ( $args['options'] as $option_value => $option_label ) : ?>
1160 <option value="<?php echo esc_attr( (string) $option_value ); ?>"><?php echo esc_html( $option_label ); ?></option>
1161 <?php endforeach; ?>
1162 <?php endif; ?>
1163 </select>
1164
1165 <?php if ( $has_icon ) : ?>
1166 </div>
1167 <?php
1168 endif;
1169 }
1170
1171 if ( $render_form_group ) {
1172 echo '</div>';
1173 }
1174 }
1175
1176 /**
1177 * Get Table Order Option
1178 *
1179 * @param int $table_id Table Id.
1180 *
1181 * @return string
1182 */
1183 function upstream_get_table_order_option( $table_id ) {
1184 $user_id = get_current_user_id();
1185
1186 return 'upstream_ordering_' . $user_id . '_' . $table_id;
1187 }
1188
1189 /**
1190 * Update Table Order
1191 *
1192 * @param mixed $table_id Table Id.
1193 * @param mixed $column Column.
1194 * @param mixed $dir Dir.
1195 */
1196 function upstream_update_table_order( $table_id, $column, $dir ) {
1197 // Update the ordering data for the table.
1198 $data = maybe_serialize(
1199 array(
1200 'column' => $column,
1201 'orderDir' => $dir,
1202 )
1203 );
1204
1205 $option = upstream_get_table_order_option( $table_id );
1206
1207 update_option( $option, $data );
1208 }
1209
1210 /**
1211 * Get Table Order
1212 *
1213 * @param int $table_id Table Id.
1214 *
1215 * @return array
1216 */
1217 function upstream_get_table_order( $table_id ) {
1218 $option = upstream_get_table_order_option( $table_id );
1219
1220 $value = maybe_unserialize( get_option( $option ) );
1221
1222 if ( ! is_array( $value ) || ! array_key_exists( 'column', $value ) || ! array_key_exists( 'orderDir', $value ) ) {
1223 $value = false;
1224 }
1225
1226 return $value;
1227 }
1228
1229 /**
1230 * Get Section Collapse State Option
1231 *
1232 * @param mixed $section Section.
1233 */
1234 function upstream_get_section_collapse_state_option( $section ) {
1235 $user_id = get_current_user_id();
1236
1237 return 'upstream_collapse_state_' . $user_id . '_' . $section;
1238 }
1239
1240 /**
1241 * Update Section Collapse State
1242 *
1243 * @param mixed $section Section.
1244 * @param mixed $state State.
1245 * @return void
1246 */
1247 function upstream_update_section_collapse_state( $section, $state ) {
1248 $option = upstream_get_section_collapse_state_option( $section );
1249
1250 $state = sanitize_text_field( $state );
1251
1252 update_option( $option, $state );
1253 }
1254
1255 /**
1256 * Get Section Collapse State
1257 *
1258 * @param mixed $section Section.
1259 */
1260 function upstream_get_section_collapse_state( $section ) {
1261 $option = upstream_get_section_collapse_state_option( $section );
1262
1263 $value = get_option( $option );
1264
1265 if ( empty( $value ) ) {
1266 $value = false;
1267 }
1268
1269 return $value;
1270 }
1271
1272 /**
1273 * Update Panel Order
1274 *
1275 * @param mixed $rows Rows.
1276 */
1277 function upstream_update_panel_order( $rows ) {
1278 $option = 'upstream_panel_order';
1279
1280 $value = array();
1281
1282 foreach ( $rows as $row ) {
1283 $row = sanitize_text_field( $row );
1284 $row = str_replace( 'project-section-', '', $row );
1285
1286 if ( ! empty( $row ) ) {
1287 $value[] = $row;
1288 }
1289 }
1290
1291 update_option( $option, $value );
1292 }
1293
1294 /**
1295 * Get Panel Order
1296 *
1297 * @return array
1298 */
1299 function upstream_get_panel_order() {
1300 return get_option( 'upstream_panel_order' );
1301 }
1302