mode(), array( 'rest', 'local', 'none' ), true ) && in_array( $d->paging(), array( 'offset', 'none' ), true ) && 'post' !== $d->search_transport();
return $fits && (bool) apply_filters( 'rooster_lms_library_table', true, $d );
}
public static function bare_eligible(): bool {
if ( ! Ui::chrome() && ! ( is_admin() && ! wp_doing_ajax() && function_exists( 'rooster_admin_builders' ) && rooster_admin_builders() ) ) {
return false;
}
return method_exists( '\Rooster\Admin\Ui', 'table' ) && (bool) apply_filters( 'rooster_lms_library_table', true, null );
}
public static function bare( array $head, string $tbody_html, string $table_class = '', string $caption = '', array $opts = array() ): string {
$columns = self::bare_columns( $head );
$rows = array();
foreach ( self::split_rows( $tbody_html ) as $parsed ) {
$rows[] = self::row( $parsed, $columns, false );
}
$html = self::head_html(
\Rooster\Admin\Ui::table(
$columns,
$rows,
self::bare_opts( $opts ) + array(
'caption' => '' !== $caption ? $caption : __( 'Table', 'rooster-lms' ),
'empty' => esc_html__( 'Nothing to show yet.', 'rooster-lms' ),
)
),
$columns
);
$class = trim( $table_class );
return '
' . $html . '
';
}
private static function bare_opts( array $opts ): array {
$out = array();
foreach ( array( 'cards', 'sticky_first', 'dense', 'striped' ) as $flag ) {
if ( ! empty( $opts[ $flag ] ) ) {
$out[ $flag ] = true;
}
}
if ( '' !== (string) ( $opts['id'] ?? '' ) ) {
$out['id'] = (string) $opts['id'];
}
return $out;
}
public static function editable( array $head, string $rows_html, string $template, string $caption, string $table_class = '', array $opts = array() ): string {
if ( ! self::bare_eligible() ) {
$heads = '';
foreach ( $head as $column ) {
$label = esc_html( $column instanceof Column ? $column->label : (string) $column );
$heads .= '' . ( $column instanceof Column && $column->sr_only ? '' . $label . '' : $label ) . ' | ';
}
return '' . esc_html( $caption ) . '' . $heads . '
' . $rows_html . '
'
. '' . $template . '';
}
$html = self::bare( $head, $rows_html, $table_class, $caption, $opts );
$html = (string) preg_replace( '#| ]*>.*? |
#s', '', $html, 1 );
$html = (string) preg_replace( '#]*)>#', '', $html, 1 );
foreach ( $head as $column ) {
if ( $column instanceof Column && $column->sr_only ) {
$label = esc_html( $column->label );
$html = str_replace( 'scope="col">' . $label . '', 'scope="col">' . $label . '', $html );
}
}
$columns = self::bare_columns( $head );
$rows = array();
foreach ( self::split_rows( $template ) as $parsed ) {
$rows[] = self::row( $parsed, $columns, false );
}
return $html . '' . \Rooster\Admin\Ui::rows( $columns, $rows, array( 'cards' => ! empty( $opts['cards'] ) ) ) . '';
}
private static function bare_columns( array $head ): array {
$columns = array();
foreach ( array_values( $head ) as $i => $column ) {
$col = $column instanceof Column ? array(
'key' => '' !== $column->key ? $column->key : 'c' . $i,
'label' => $column->label,
'type' => 'html',
'align' => in_array( $column->align, array( 'start', 'center', 'end' ), true ) ? $column->align : 'start',
) : array(
'key' => 'c' . $i,
'label' => (string) $column,
'type' => 'html',
);
if ( $column instanceof Column && '' !== $column->html ) {
$col['head_html'] = $column->html;
}
if ( $column instanceof Column && '' !== $column->width ) {
$col['width'] = $column->width;
}
if ( $column instanceof Column ) {
$col += self::phone( $column );
}
$columns[] = $col;
}
return $columns;
}
private static function phone( Column $column ): array {
$out = array();
if ( 'low' === $column->priority ) {
$out['priority'] = 'low';
}
if ( '' !== $column->group ) {
$out['group'] = $column->group;
}
return $out;
}
public static function frame( TableDefinition $d, TableQuery $q ): string {
if ( ! $d->can_view( get_current_user_id(), $d->context() ) ) {
return '';
}
list( $q, $page ) = DataTable::page_of( $d, $q );
if ( is_admin() ) {
Assets::enqueue_row_actions();
}
if ( method_exists( '\Rooster\Admin\States', 'enqueue' ) && wp_script_is( 'rooster-admin-chrome', 'registered' ) ) {
\Rooster\Admin\States::enqueue();
}
$id = self::dom_id( $d );
$columns = self::columns( $d, $q );
$bulk = array_values( array_filter( $d->bulk(), static fn( $b ): bool => $b instanceof BulkAction ) );
$names = TableQuery::arg_names( $d );
$view = self::view_key( $d );
$filters = self::filters( $d, $view );
$views = $d->table_views();
$opts = array(
'id' => $id,
'caption' => '' !== $d->caption() ? $d->caption() : __( 'Table', 'rooster-lms' ),
'empty' => esc_html( $d->empty_text( $q->filtered() ) ),
'selectable' => array() !== $bulk,
);
if ( array() !== $filters ) {
$opts['filters'] = $filters;
$opts['filter_values'] = self::filter_values( $d, $q, $filters );
}
$opts['typed'] = $q->search;
$opts += self::kind_opts( $d );
if ( '' !== $d->search_label() ) {
$opts['search'] = array(
'label' => $d->search_label(),
'placeholder' => $d->search_label(),
);
if ( array() === $filters ) {
$opts['filters'] = array();
}
}
$toolbar = self::toolbar( $d, $q, $page );
if ( '' !== $toolbar ) {
$opts['toolbar'] = $toolbar;
}
$export = self::export( $d, $id );
if ( array() !== $export ) {
$opts['export'] = $export;
}
$chooser = self::chooser( $columns );
if ( null !== $chooser ) {
$opts['chooser'] = $chooser;
}
if ( $d->text_size() ?? count( $columns ) >= 7 ) {
$opts['text_size'] = true;
}
$dialogs = '';
if ( array() !== $bulk ) {
list( $opts['bulk'], $dialogs ) = self::bulk( $bulk, $id );
}
list( $by, $dir ) = '' !== $q->orderby ? array( $q->orderby, $q->order ) : $d->default_order();
$sizes = 'offset' === $d->paging() ? array_values( array_unique( array_map( 'intval', $d->per_page_options() ) ) ) : array();
$whole = self::whole( $d, $q, $page, $view, $columns );
if ( null !== $whole ) {
$sorts = $d->local_sorts();
$default = $d->default_order();
foreach ( $columns as $i => $col ) {
if ( isset( $col['sort'], $sorts[ (string) $col['key'] ]['type'] ) ) {
$columns[ $i ]['sort_type'] = (string) $sorts[ (string) $col['key'] ]['type'];
}
}
$opts['local'] = array(
'size' => $q->per_page,
'asked' => $q->per_page,
'sizes' => count( $sizes ) > 1 ? $sizes : array(),
'paged' => $q->page,
'keys' => array(
's' => $names['search'],
'orderby' => $names['orderby'],
'order' => $names['order'],
'paged' => $names['page'],
'per_page' => $names['per_page'],
),
'prefix' => $d->arg_prefix(),
'tie' => 'asc' === ( $sorts[ (string) $by ]['tie'] ?? '' ) ? 'asc' : 'dir',
);
if ( '' !== (string) $default[0] ) {
$opts['local']['sort'] = array(
'key' => (string) $default[0],
'dir' => 'desc' === $default[1] ? 'desc' : 'asc',
);
}
$rows = self::rows( $d, $page->rows, $columns, array() !== $bulk, true );
$opts['rows_template'] = self::rows( $d, $whole->rows, $columns, array() !== $bulk, true );
} elseif ( 'offset' === $d->paging() && null !== TableRegistry::get( $d->id(), $d->context() ) ) {
$opts['remote'] = array(
'url' => esc_url_raw( rest_url( 'rooster-lms/v1/tables/' . $d->id() . '/rows' ) ),
'nonce' => wp_create_nonce( 'wp_rest' ),
'scope' => self::scope( $d, $q, $view, $id ),
'context' => 'admin',
'size' => $q->per_page,
'asked' => $q->per_page,
'sizes' => count( $sizes ) > 1 ? $sizes : array(),
'total' => null !== $page->total ? (int) $page->total : count( $page->rows ),
'paged' => $q->page,
'sort' => '' !== (string) $by ? array(
'key' => (string) $by,
'dir' => 'desc' === $dir ? 'desc' : 'asc',
) : null,
'keys' => array(
's' => $names['search'],
'orderby' => $names['orderby'],
'order' => $names['order'],
'paged' => $names['page'],
'per_page' => $names['per_page'],
),
'prefix' => $d->arg_prefix(),
);
} elseif ( 'offset' === $d->paging() ) {
$opts['footer'] = Pager::offset( $q->page, max( 1, (int) ceil( (int) $page->total / max( 1, $q->per_page ) ) ), static fn( int $n ): string => $q->url( $d, array( 'page' => $n ) ) );
}
if ( null === $whole ) {
$rows = self::rows( $d, $page->rows, $columns, array() !== $bulk );
}
$html = self::head_html( \Rooster\Admin\Ui::table( $columns, $rows, $opts ), $columns );
if ( array() !== $bulk ) {
$html .= '';
}
if ( array() !== $bulk || array() !== array_filter( $d->exports(), static fn( $e ): bool => $e instanceof ExportLink && ExportLink::REST_TOKEN === $e->kind ) ) {
Assets::enqueue_table_library();
}
$lifted = self::$lifted;
self::$lifted = '';
return '' . ( null !== $views ? $views->html() : '' ) . $html . '
' . $dialogs . $lifted;
}
private static function kind_opts( TableDefinition $d ): array {
switch ( $d->kind() ) {
case 'list':
return array( 'cards' => true );
case 'grid':
return array( 'sticky_first' => true );
default:
return array();
}
}
public static function answer( TableDefinition $d, array $params ): array {
$names = TableQuery::arg_names( $d );
$get = array(
$names['page'] => $params['page'] ?? 1,
$names['per_page'] => $params['per_page'] ?? 0,
$names['orderby'] => $params['orderby'] ?? '',
$names['order'] => $params['order'] ?? '',
$names['search'] => $params['search'] ?? '',
);
$given = array_merge( is_array( $params['fixed'] ?? null ) ? $params['fixed'] : array(), is_array( $params['params'] ?? null ) ? $params['params'] : array() );
foreach ( $d->filters() as $filter ) {
if ( ! array_key_exists( $filter->key, $given ) ) {
continue;
}
$value = $given[ $filter->key ];
if ( Filter::MULTI !== $filter->type && is_array( $value ) ) {
$value = (string) ( array_values( $value )[0] ?? '' );
}
$get[ $names['filters'][ $filter->key ] ] = $value;
}
list( $q, $page ) = DataTable::page_of( $d, TableQuery::from_args( $d, $get ) );
$columns = self::columns( $d, $q );
$total = null !== $page->total ? (int) $page->total : ( $q->offset() + count( $page->rows ) + ( $page->more ? 1 : 0 ) );
$answer = \Rooster\Admin\Ui::answer(
$columns,
self::rows( $d, $page->rows, $columns, array() !== $d->bulk() ),
array(
'total' => $total,
'filtered' => $total,
'page' => $q->page,
'per_page' => $q->per_page,
'pages' => max( 1, (int) ceil( $total / max( 1, $q->per_page ) ) ),
'orderby' => $q->orderby,
'order' => $q->order,
),
array(
'selectable' => array() !== $d->bulk(),
'cards' => 'list' === $d->kind(),
)
);
$form = (string) ( $params['form'] ?? '' );
$answer['rows'] = self::rl_ids( (string) ( $answer['rows'] ?? '' ), 1 === preg_match( '/^[A-Za-z0-9_-]{1,80}$/', $form ) ? $form : '' );
return $answer + array( 'empty' => $d->empty_text( $q->filtered() ) );
}
private static function rl_ids( string $html, string $form ): string {
return str_replace( 'columns(), static fn( $c ): bool => $c instanceof Column ) ), 0, DataTable::MAX_COLUMNS ) as $column ) {
$col = array(
'key' => $column->key,
'label' => $column->label,
'type' => 'html',
'align' => in_array( $column->align, array( 'start', 'center', 'end' ), true ) ? $column->align : 'start',
);
if ( ! $column->hideable || '' === $column->label ) {
$col['always'] = true;
}
if ( '' !== $column->html ) {
$col['head_html'] = $column->html;
}
if ( '' !== $column->width ) {
$col['width'] = $column->width;
}
$col += self::phone( $column );
$col['shown'] = $column->visible;
if ( $column->sortable ) {
$current = $q->orderby === $column->key;
$col['sort'] = $current ? ( 'desc' === $q->order ? 'desc' : 'asc' ) : '';
$col['sort_url'] = $q->url(
$d,
array(
'orderby' => $column->key,
'order' => $current && 'asc' === $q->order ? 'desc' : 'asc',
'page' => 1,
)
);
}
$out[] = $col;
}
return $out;
}
private static function head_html( string $html, array $columns ): string {
foreach ( $columns as $col ) {
if ( '' === (string) ( $col['head_html'] ?? '' ) || isset( $col['sort'] ) ) {
continue;
}
$label = esc_html( (string) $col['label'] );
$at = strpos( $html, 'scope="col">' . $label . '' );
if ( false !== $at ) {
$html = substr_replace( $html, 'scope="col">' . $col['head_html'] . '' . $label . '', $at, strlen( 'scope="col">' . $label . '' ) );
}
}
return $html;
}
private static function chooser( array $columns ): ?array {
$hideable = array_filter( array_slice( $columns, 1 ), static fn( array $c ): bool => empty( $c['always'] ) );
if ( array() === $hideable ) {
return null;
}
return array( 'shown' => array_values( array_map( static fn( array $c ): string => (string) $c['key'], array_filter( $columns, static fn( array $c ): bool => ! empty( $c['shown'] ) ) ) ) );
}
private static function rows( TableDefinition $d, array $source, array $columns, bool $bulk, bool $local = false ): array {
$out = array();
foreach ( $source as $item ) {
$tr = $d->row( $item );
if ( '' === trim( $tr ) ) {
continue;
}
$values = $local ? self::local_values( $d, $item ) : array();
foreach ( self::split_rows( $tr ) as $parsed ) {
$row = self::row( $parsed, $columns, $bulk );
if ( array() !== $values ) {
$row['_attrs'] = $values + ( $row['_attrs'] ?? array() );
}
if ( $local ) {
$row = self::lift_dialogs( $row );
}
$out[] = $row;
}
}
return $out;
}
private static function lift_dialogs( array $row ): array {
$lift = static function ( string $html ): string {
return (string) preg_replace_callback(
'##s',
static function ( array $m ): string {
self::$lifted .= $m[0];
return '';
},
$html
);
};
foreach ( $row as $key => $cell ) {
if ( '_span' === $key && is_string( $cell ) ) {
$row[ $key ] = $lift( $cell );
} elseif ( '_' !== substr( (string) $key, 0, 1 ) && is_array( $cell ) && isset( $cell['html'] ) ) {
$row[ $key ]['html'] = $lift( (string) $cell['html'] );
}
}
return $row;
}
private static function local_values( TableDefinition $d, mixed $item ): array {
$out = array();
$values = array();
foreach ( $d->filter_values( $item ) as $key => $list ) {
$values[ (string) $key ] = array_values( array_map( 'strval', (array) $list ) );
}
if ( array() !== $values ) {
$out['data-ra-f'] = $values;
}
if ( array() !== $d->local_sorts() ) {
$out['data-ra-s'] = $d->sort_values( $item );
}
$text = $d->search_text( $item );
if ( '' !== $text ) {
$out['data-ra-text'] = $text;
}
return $out;
}
private static function whole( TableDefinition $d, TableQuery $q, TablePage $page, string $view, array $columns ): ?TablePage {
if ( 'offset' !== $d->paging() || $d->local_cap() <= 0 ) {
return null;
}
$local = $d->local_filters();
foreach ( $d->filters() as $filter ) {
if ( $filter instanceof Filter && $filter->key !== $view && ( ! isset( $local[ $filter->key ] ) || array() !== (array) $local[ $filter->key ] ) ) {
return null;
}
}
$sorts = $d->local_sorts();
foreach ( $columns as $col ) {
if ( isset( $col['sort'] ) && ! isset( $sorts[ (string) $col['key'] ] ) ) {
return null;
}
}
$clear = array();
foreach ( array_keys( $local ) as $key ) {
$set = $q->filter( (string) $key );
if ( (string) $key !== $view && '' !== $set && array() !== $set ) {
$clear[ (string) $key ] = null;
}
}
$cap = $d->local_cap();
if ( 1 === $q->page && '' === $q->search && array() === $clear && null !== $page->total && count( $page->rows ) >= $page->total ) {
$read = $page;
} else {
$read = $d->source()->page(
$q->with(
array(
'page' => 1,
'per_page' => $cap,
'known_total' => null,
'search' => '',
'filters' => $clear,
)
)
);
}
if ( null === $read->total || $read->total > $cap || count( $read->rows ) < $read->total ) {
return null;
}
if ( '' !== $d->search_label() && array() !== $read->rows && '' === $d->search_text( $read->rows[ array_key_first( $read->rows ) ] ) ) {
return null;
}
return $read;
}
private static function row( array $parsed, array $columns, bool $bulk ): array {
$row = array();
$attrs = array();
foreach ( $parsed['attrs'] as $name => $value ) {
if ( str_starts_with( $name, 'data-' ) && 'data-ra-row' !== $name ) {
$attrs[ $name ] = $value;
}
}
$class = ' ' . ( $parsed['attrs']['class'] ?? '' ) . ' ';
if ( ' ' !== $class ) {
$attrs['data-rl-class'] = trim( $class );
}
$cells = $parsed['cells'];
if ( $bulk && isset( $cells[0] ) && 1 === preg_match( '/]*\bname="rl_ids\[\]"[^>]*\bvalue="(\d+)"/', $cells[0]['html'], $m ) ) {
$row['_id'] = $m[1];
array_shift( $cells );
} elseif ( $bulk && isset( $cells[0] ) && str_contains( $cells[0]['attrs']['class'] ?? '', 'rooster-lms-table__check' ) ) {
array_shift( $cells );
}
if ( 1 === count( $cells ) && (int) ( $cells[0]['attrs']['colspan'] ?? 1 ) > 1 ) {
$row['_span'] = $cells[0]['html'];
} else {
$i = 0;
foreach ( $cells as $cell ) {
if ( ! isset( $columns[ $i ] ) ) {
break;
}
$span = max( 1, (int) ( $cell['attrs']['colspan'] ?? 1 ) );
$row[ (string) $columns[ $i ]['key'] ] = $span > 1 ? array(
'html' => self::cell_html( $cell ),
'colspan' => $span,
) : array( 'html' => self::cell_html( $cell ) );
$i += $span;
}
}
if ( array() !== $attrs ) {
$row['_attrs'] = $attrs;
}
return $row;
}
private static function cell_html( array $cell ): string {
$own = array_diff( explode( ' ', (string) preg_replace( '/\s+/', ' ', trim( $cell['attrs']['class'] ?? '' ) ) ), array( '', 'num', 'is-num', 'rooster-lms-table__check' ) );
return array() === $own ? $cell['html'] : '' . $cell['html'] . '
';
}
public static function split_rows( string $html ): array {
$out = array();
if ( false === preg_match_all( '#<(/?)(tr|td|th|table)\b((?:[^>"\']|"[^"]*"|\'[^\']*\')*)>#i', $html, $tags, PREG_SET_ORDER | PREG_OFFSET_CAPTURE ) ) {
return $out;
}
$depth = 0;
$row = null;
$cell = null;
foreach ( $tags as $tag ) {
$close = '/' === $tag[1][0];
$name = strtolower( $tag[2][0] );
$at = (int) $tag[0][1];
$end = $at + strlen( $tag[0][0] );
if ( 'table' === $name ) {
$depth += $close ? -1 : 1;
continue;
}
if ( $depth > 0 ) {
continue;
}
if ( 'tr' === $name ) {
if ( ! $close ) {
$row = array(
'attrs' => self::attrs( $tag[3][0] ),
'cells' => array(),
);
} elseif ( null !== $row ) {
$out[] = $row;
$row = null;
}
continue;
}
if ( null === $row ) {
continue;
}
if ( ! $close ) {
$cell = array(
'tag' => $name,
'attrs' => self::attrs( $tag[3][0] ),
'from' => $end,
);
} elseif ( null !== $cell ) {
$row['cells'][] = array(
'tag' => $cell['tag'],
'attrs' => $cell['attrs'],
'html' => substr( $html, $cell['from'], $at - $cell['from'] ),
);
$cell = null;
}
}
return $out;
}
private static function attrs( string $source ): array {
$out = array();
if ( preg_match_all( '#([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:"([^"]*)"|\'([^\']*)\'|([^\s"\'=<>`]+)))?#', $source, $m, PREG_SET_ORDER ) ) {
foreach ( $m as $a ) {
$value = $a[2] ?? '';
$value = '' !== $value ? $value : ( $a[3] ?? '' );
$value = '' !== $value ? $value : ( $a[4] ?? '' );
$out[ strtolower( $a[1] ) ] = html_entity_decode( $value, ENT_QUOTES | ENT_HTML5, 'UTF-8' );
}
}
return $out;
}
private static function filter_values( TableDefinition $d, TableQuery $q, array $decl ): array {
if ( ! class_exists( '\Rooster\Admin\Filters' ) ) {
return array();
}
$names = TableQuery::arg_names( $d );
$source = array();
foreach ( $q->filters as $key => $value ) {
if ( isset( $names['filters'][ $key ] ) && null !== $value && '' !== $value && array() !== $value ) {
$source[ $names['filters'][ $key ] ] = $value;
}
}
return \Rooster\Admin\Filters::values( $decl, $d->arg_prefix(), $source );
}
private static function filters( TableDefinition $d, string $view ): array {
$out = array();
foreach ( $d->filters() as $filter ) {
if ( ! $filter instanceof Filter || $filter->key === $view ) {
continue;
}
$options = array();
$any = '';
foreach ( $filter->options as $value => $label ) {
if ( '' === (string) $value ) {
$any = (string) $label;
continue;
}
$options[ (string) $value ] = (string) $label;
}
if ( Filter::TOGGLE === $filter->type ) {
$decl = array(
'key' => $filter->key,
'label' => $filter->label,
'control' => 'checks',
'options' => array_slice( $options, 0, 1, true ),
);
} else {
$decl = array(
'key' => $filter->key,
'label' => $filter->label,
'control' => Filter::MULTI === $filter->type ? 'chips' : ( count( $options ) > 15 ? 'combo' : 'select' ),
'options' => $options,
);
if ( '' !== $any ) {
$decl['any'] = $any;
}
}
$out[] = $decl;
}
return $out;
}
private static function toolbar( TableDefinition $d, TableQuery $q, TablePage $page ): string {
$html = '';
foreach ( $d->chips() as $chip ) {
$key = (string) ( $chip['key'] ?? '' );
$value = (string) ( $chip['value'] ?? '' );
$on = $q->filter( $key ) === $value;
$count = $page->counts[ $key ][ $value ] ?? null;
$html .= \Rooster\Admin\Ui::button(
(string) ( $chip['label'] ?? $value ) . ( null !== $count ? ' (' . \RoosterLMS\I18n\Format::number( (int) $count ) . ')' : '' ),
array(
'variant' => $on ? 'primary' : 'outline',
'size' => 'sm',
'href' => $q->url(
$d,
array(
'filters' => array( $key => $on ? null : $value ),
'page' => 1,
)
),
'attrs' => $on ? array( 'aria-current' => 'true' ) : array(),
)
);
}
return $html;
}
private static function export( TableDefinition $d, string $id ): array {
$out = array();
foreach ( $d->exports() as $export ) {
if ( ! $export instanceof ExportLink || ! in_array( $export->format, array( 'csv', 'xlsx' ), true ) ) {
continue;
}
if ( ExportLink::URL === $export->kind ) {
$out[ $export->format ] = $export->target;
if ( $export->shown ) {
$out['columns'] = 'visible';
}
if ( $export->sheets && 'xlsx' === $export->format ) {
$out['views'] = 'sheets';
}
continue;
}
$out[ $export->format ] = '';
$out['attrs'] = array(
'data-rl-export' => $export->target,
'data-rl-map' => (string) wp_json_encode( (object) $export->map ),
'data-rl-export-for' => $id,
);
}
if ( array() !== $out ) {
$out['scope'] = isset( $out['columns'] )
? __( 'Exports every row that matches the filters and the search, with the columns shown', 'rooster-lms' )
: __( 'Exports every row that matches the filters and the search, every column', 'rooster-lms' );
if ( isset( $out['views'] ) ) {
$out['sheets'] = __( 'Excel: every view as a sheet', 'rooster-lms' );
}
$out['id'] = $id . '-export';
}
return $out;
}
private static function bulk( array $actions, string $id ): array {
$bar = '';
$dialogs = '';
foreach ( $actions as $action ) {
$attrs = array(
'data-rl-bulk' => $action->key,
'form' => $id . '-bulk',
);
if ( '' !== $action->confirm ) {
$dialog = $id . '-confirm-' . sanitize_html_class( $action->key );
$danger = 'destructive' === $action->variant;
$dialogs .= \Rooster\Admin\States::confirm(
$dialog,
$danger ? 'delete' : 'apply',
$action->confirm,
/* translators: %s: the number of rows (a figure the table fills in). */
sprintf( esc_html__( 'Rows selected: %s.', 'rooster-lms' ), '0' ),
array( 'confirm' => $action->label )
);
$attrs += self::confirm_attrs( $dialog );
}
$bar .= \Rooster\Admin\Ui::button(
$action->label,
array(
'variant' => array(
'secondary' => 'outline',
'dim' => 'ghost',
)[ $action->variant ] ?? $action->variant,
'size' => 'sm',
'attrs' => $attrs,
)
);
}
return array( $bar, $dialogs );
}
public static function confirm_attrs( string $dialog ): array {
$attrs = \Rooster\Admin\States::confirm_attrs( $dialog );
if ( ! wp_script_is( 'rooster-admin-chrome', 'registered' ) ) {
wp_dequeue_script( 'rooster-admin-states' );
}
return $attrs;
}
private static function scope( TableDefinition $d, TableQuery $q, string $view, string $id ): array {
$scope = array( 'ctx' => (string) wp_json_encode( (object) $d->context() ) );
if ( array() !== $d->bulk() ) {
$scope['form'] = $id . '-bulk';
}
$lang = Switcher::current();
if ( '' !== $lang ) {
$scope['lang'] = $lang;
}
if ( '' !== $view ) {
$value = $q->filter( $view );
if ( is_string( $value ) && '' !== $value ) {
$scope['fixed'] = (string) wp_json_encode( array( $view => $value ) );
}
}
return $scope;
}
private static function view_key( TableDefinition $d ): string {
$views = $d->table_views();
if ( null === $views ) {
return '';
}
$key = array_search( $views->arg, TableQuery::arg_names( $d )['filters'], true );
return is_string( $key ) ? $key : '';
}
private static function dom_id( TableDefinition $d ): string {
$base = 'rl-' . sanitize_html_class( str_replace( '.', '-', $d->id() ) );
self::$ids[ $base ] = ( self::$ids[ $base ] ?? 0 ) + 1;
return 1 === self::$ids[ $base ] ? $base : $base . '-' . self::$ids[ $base ];
}
}