-1:false;}).map(function(c){return c.index;}).join(" "));var b=f.querySelectorAll("[data-rl-column]"),w=f.querySelector("[data-rl-columns-words]"),x=w?parseInt(w.getAttribute("data-rl-columns-fixed"),10)||0:0,n=x;b.forEach(function(e){e.checked=-1===p.hide.indexOf(e.getAttribute("data-rl-column"));if(e.checked){n++;}});if(w?(w.lastChild?3===w.lastChild.nodeType:false):false){w.lastChild.nodeValue=w.getAttribute("data-rl-columns-words").replace("%%1$s",n).replace("%%2$s",x+b.length);}}if(p.compact){t.classList.add("rooster-lms-table--compact");var d=f.querySelector("[data-rl-density]");if(d){d.setAttribute("aria-pressed","true");}}}catch(e){}})(document.getElementById(%s));'; private static array $early = array(); public static function early_prefs( string $html ): string { if ( ! str_contains( $html, 'rooster-lms-table-frame' ) || ! preg_match_all( '/\bid="(rooster-lms-table-\d+)"[^>]*\bclass="rooster-lms rooster-lms-table-frame\b/', $html, $m ) ) { return $html; } foreach ( array_unique( $m[1] ) as $uid ) { if ( ! isset( self::$early[ $uid ] ) ) { self::$early[ $uid ] = true; $html = EarlyScripts::after( $html, sprintf( self::PREFS_JS, wp_json_encode( $uid ) ) ); } } return $html; } public static function display( TableDefinition $d, ?TableQuery $q = null ): void { list( $html, $uid ) = self::frame( $d, $q ); if ( '' === $html ) { return; } echo wp_kses( $html, Kses::current() ); if ( '' !== $uid ) { wp_print_inline_script_tag( sprintf( self::PREFS_JS, wp_json_encode( $uid ) ) ); } } public static function render( TableDefinition $d, ?TableQuery $q = null ): string { list( $html, $uid ) = self::frame( $d, $q ); if ( '' !== $uid ) { wp_add_inline_script( Assets::TABLE, sprintf( self::PREFS_JS, wp_json_encode( $uid ) ), 'before' ); } return $html; } private static function frame( TableDefinition $d, ?TableQuery $q ): array { if ( ! $d->can_view( get_current_user_id(), $d->context() ) ) { return array( '', '' ); } $q = $q ?? TableQuery::from_request( $d ); if ( LibraryTable::eligible( $d ) ) { return array( LibraryTable::frame( $d, $q ), '' ); } $whole = self::whole( $d, $q, null ); list( $q, $page ) = self::read( $d, $q ); $whole = $whole ?? self::whole( $d, $q, $page ); Assets::enqueue_table( $d->mode(), $d->search_live() ); if ( self::searchable( $d, $page ) || '' !== $whole ) { Assets::enqueue_table_search(); } if ( is_admin() ) { Assets::enqueue_row_actions(); } ++self::$count; $uid = 'rooster-lms-table-' . self::$count; $caption = '' !== $d->caption() ? $d->caption() : __( 'Table', 'rooster-lms' ); $columns = self::columns( $d ); $bulk = $d->bulk(); $attrs = array( 'id' => $uid, 'class' => 'rooster-lms rooster-lms-table-frame', 'data-rl-table' => $d->id(), 'data-rl-mode' => $d->mode(), 'data-rl-state' => (string) wp_json_encode( self::state( $d, $q, $page, '' !== $whole ) ), 'data-rl-i18n' => (string) wp_json_encode( self::strings( $d ) ), 'data-rl-paging' => $d->paging(), ); if ( $d->search_live() ) { $attrs['data-rl-search-live'] = '1'; } $view_key = self::view_filter( $d ); if ( '' !== $view_key ) { $attrs['data-rl-views'] = $view_key; } if ( 'router' === $d->mode() && $d->live_frame() ) { $attrs['data-rl-rest'] = self::live_config( $d ); if ( null !== $page->total ) { $attrs['data-rl-token'] = CountToken::issue( $d->id(), $d->context(), $q->hash(), array( 'n' => $page->total ) ); } } $html = ''; $html .= self::toolbar( $d, $q, $uid, $columns ); $html .= '' . self::chips( $d, $q, $page ) . ''; $html .= ''; if ( array() !== $bulk ) { $html .= '
'; foreach ( $d->bulk_fields() as $name => $value ) { $html .= ''; } } $html .= '
'; $html .= ''; $html .= 'show_caption() ? '' : ' class="screen-reader-text"' ) . '>' . esc_html( $caption ) . ''; $html .= '' . self::head( $d, $q, $columns ) . ''; $html .= '' . self::body( $d, $q, $page, $columns ) . ''; $html .= '
' . $whole; if ( array() !== $bulk ) { $html .= '

'; } $html .= ''; $html .= self::footer( $d, $q, $page, $uid ); $html .= ''; return array( $html, $uid ); } public static function fragment( TableDefinition $d, TableQuery $q ): array { $all = null; $whole = self::whole( $d, $q, null, $all ); if ( null !== $all && '' !== (string) $whole ) { list( $q, $page ) = self::local_page( $d, $q, $all ); } else { list( $q, $page ) = self::read( $d, $q ); } $columns = self::columns( $d ); $whole = $whole ?? self::whole( $d, $q, $page ); return array( 'whole' => $whole, 'thead' => self::head( $d, $q, $columns ), 'tbody' => self::body( $d, $q, $page, $columns ), 'pager' => self::pager( $d, $q, $page ), 'summary' => self::summary( $q, $page ), 'chips' => self::chips( $d, $q, $page ), 'total' => $page->total, 'page' => $q->page, 'pages' => self::pages( $q, $page ), 'more' => $page->more, 'after' => $page->after, 'state' => self::state( $d, $q, $page, '' !== $whole ), ); } private static function whole( TableDefinition $d, TableQuery $q, ?TablePage $page, ?TablePage &$all = null ): ?string { $local = $d->local_filters(); if ( array() === $local || 'offset' !== $d->paging() || '' !== $q->search ) { return ''; } $clear = array(); foreach ( $local as $key => $server_only ) { $value = $q->filters[ $key ] ?? ''; if ( '' === $value || array() === $value ) { continue; } if ( array_intersect( array_map( 'strval', (array) $value ), array_map( 'strval', (array) $server_only ) ) ) { return ''; } $clear[ $key ] = null; } if ( null === $page && array() === $clear ) { return null; } $cap = max( $q->per_page, $d->local_cap() ); if ( null !== $page && ( null === $page->total || $page->total > $cap ) ) { return ''; } $whole = array( 'page' => 1, 'per_page' => $cap, 'known_total' => null, ); if ( null === $page ) { $read = $d->source()->page( $q->with( $whole + array( 'filters' => $clear ) ) ); } elseif ( 1 === $q->page && count( $page->rows ) >= (int) $page->total ) { $read = $page; } else { $read = $d->source()->page( $q->with( $whole ) ); } if ( null === $read->total || $read->total > $cap || count( $read->rows ) < $read->total ) { return ''; } if ( null === $page ) { $all = $read; } $sorts = array() !== $d->local_sorts(); $rows = ''; foreach ( $read->rows as $row ) { $tr = $d->row( $row ); if ( '' === $tr ) { continue; } $values = array(); foreach ( $d->filter_values( $row ) as $key => $list ) { $values[ (string) $key ] = array_values( array_map( 'strval', (array) $list ) ); } $attrs = ' data-ra-f="' . esc_attr( (string) wp_json_encode( (object) $values, JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_TAG ) ) . '"'; if ( $sorts ) { $attrs .= ' data-ra-s="' . esc_attr( (string) wp_json_encode( (object) $d->sort_values( $row ), JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_TAG ) ) . '"'; } $rows .= (string) preg_replace( '/^' . $rows . ''; } private static function local_page( TableDefinition $d, TableQuery $q, TablePage $all ): array { $first = array(); foreach ( $d->filters() as $filter ) { $keys = array_keys( $filter->options ); $first[ $filter->key ] = isset( $keys[0] ) ? (string) $keys[0] : ''; } $asked = array(); foreach ( array_keys( $d->local_filters() ) as $key ) { $value = $q->filters[ $key ] ?? ''; if ( '' === $value || array() === $value || ( ! is_array( $value ) && '0' === (string) $value && '0' === ( $first[ $key ] ?? '' ) ) ) { continue; } $asked[ $key ] = array_map( 'strval', (array) $value ); } $rows = array_values( array_filter( $all->rows, static function ( $row ) use ( $d, $asked ): bool { $values = $d->filter_values( $row ); foreach ( $asked as $key => $want ) { if ( array() === array_intersect( $want, array_map( 'strval', (array) ( $values[ $key ] ?? array() ) ) ) ) { return false; } } return true; } ) ); $per = max( 1, $q->per_page ); $last = max( 1, (int) ceil( count( $rows ) / $per ) ); $q = $q->with( array( 'page' => min( max( 1, $q->page ), $last ), 'known_total' => count( $rows ), ) ); return array( $q, new TablePage( array_slice( $rows, ( $q->page - 1 ) * $per, $per ), count( $rows ), false, '', $all->counts ) ); } public static function page_of( TableDefinition $d, TableQuery $q ): array { return self::read( $d, $q ); } private static function read( TableDefinition $d, TableQuery $q ): array { $page = $d->source()->page( $q ); if ( 'offset' === $d->paging() && array() === $page->rows && null !== $page->total && $page->total > 0 && $q->page > 1 ) { $last = max( 1, (int) ceil( $page->total / max( 1, $q->per_page ) ) ); if ( $q->page > $last ) { $q = $q->with( array( 'page' => $last, 'known_total' => $page->total, ) ); $page = $d->source()->page( $q ); } } return array( null === $page->total ? $q : $q->with( array( 'known_total' => $page->total ) ), $page ); } public static function live_config( TableDefinition $d, array $attrs = array() ): string { return (string) wp_json_encode( array( 'url' => TreeTable::user_locale( esc_url_raw( rest_url( 'rooster-lms/v1/tables/' . $d->id() . '/live' ) ) ), 'nonce' => wp_create_nonce( 'wp_rest' ), 'lang' => Switcher::current(), 'context' => (object) $d->context(), 'attrs' => (object) array_map( 'intval', $attrs ), ) ); } public static function number_frames_from( int $n ): void { self::$count = max( 0, $n - 1 ); } public static function bare( array $head, string $tbody_html, string $table_class = '', string $caption = '', array $opts = array() ): string { if ( LibraryTable::bare_eligible() ) { return LibraryTable::bare( $head, $tbody_html, $table_class, $caption, $opts ); } Assets::enqueue_styles(); $num = array(); $center = array(); $cells = ''; foreach ( array_values( $head ) as $i => $column ) { if ( $column instanceof Column ) { if ( 'end' === $column->align ) { $num[] = $i + 1; } elseif ( 'center' === $column->align ) { $center[] = $i + 1; } $cells .= self::plain_head( $column ); } else { $cells .= '' . esc_html( (string) $column ) . ''; } } $attrs = array( 'class' => trim( 'rooster-lms-table ' . $table_class ) ); if ( array() !== $num ) { $attrs['data-rl-num'] = implode( ' ', $num ); } if ( array() !== $center ) { $attrs['data-rl-center'] = implode( ' ', $center ); } $html = '
'; $html .= ''; if ( '' !== $caption ) { $html .= '' . esc_html( $caption ) . ''; } $html .= '' . $cells . '' . $tbody_html . '
'; return $html; } public static function display_bare( array $head, string $tbody_html, string $table_class = '', string $caption = '', array $opts = array() ): void { echo wp_kses( self::bare( $head, $tbody_html, $table_class, $caption, $opts ), Kses::current() ); } public static function check_cell( int $id, string $label ): string { return ''; } public static function live_part( string $key, string $classes, string $inner, array $attrs = array() ): string { $attrs = array( 'class' => $classes, 'data-rl-live' => $key, ) + $attrs + array( 'data-rl-stamp' => self::stamp() ); return '' . $inner . ''; } public static function search_button( string $label ): string { return ''; } public static function clear_button( string $url, bool $active, string $scope = 'all' ): string { return ''; } public static function nojs_submit( string $label, string $form = '' ): string { return ''; } private static function live_attrs( TableDefinition $d, string $part, string $classes ): string { $attrs = array( 'class' => $classes, 'data-rl-live' => $d->id() . ':' . $part, ); if ( 'router' === $d->mode() ) { $attrs['data-wp-interactive'] = $d->interactive(); $attrs['data-wp-router-region'] = 'rooster-lms-table-' . sanitize_html_class( str_replace( '.', '-', $d->id() ) ) . ( 'rows' === $part ? '' : '-' . $part ); } $attrs['data-rl-stamp'] = self::stamp(); return self::attrs( $attrs ); } private static function stamp(): string { static $stamp = ''; if ( '' === $stamp ) { $stamp = bin2hex( random_bytes( 5 ) ); } return $stamp; } private static function columns( TableDefinition $d ): array { return array_slice( array_values( array_filter( $d->columns(), static fn( $c ): bool => $c instanceof Column ) ), 0, self::MAX_COLUMNS ); } private static function state( TableDefinition $d, TableQuery $q, TablePage $page, bool $whole = false ): array { $offset = array() !== $d->bulk() ? 1 : 0; $columns = array(); foreach ( self::columns( $d ) as $i => $column ) { $columns[] = array( 'key' => $column->key, 'label' => $column->label, 'index' => $i + 1 + $offset, 'hideable' => $column->hideable, 'visible' => $column->visible, ); } list( $default_by, $default_order ) = $d->default_order(); return array( 'id' => $d->id(), 'args' => TableQuery::arg_names( $d ), 'base' => TableQuery::strip( $d, $d->base_url() ), 'page' => $q->page, 'per_page' => $q->per_page, 'orderby' => $q->orderby, 'order' => $q->order, 'filters' => (object) $q->filters, 'after' => $q->after, 'next' => $page->after, 'total' => $page->total, 'hash' => $q->hash(), 'context' => (object) $q->context, 'defaults' => array( 'orderby' => (string) $default_by, 'order' => 'desc' === $default_order ? 'desc' : 'asc', 'per_page' => TableQuery::from_state( $d, array(), $q->context )->per_page, ), 'columns' => $columns, 'search' => '' !== $d->search_label() ? $d->search_transport() : '', 'lang' => self::language( $d ), 'client' => self::client( $d, $q, $page ), 'local' => $whole ? (object) array_map( static fn( $v ): array => array_values( array_map( 'strval', (array) $v ) ), $d->local_filters() ) : false, 'sorts' => $whole ? (object) $d->local_sorts() : (object) array(), 'listed' => array( 'orderby' => $q->orderby, 'order' => $q->order, ), ); } private static function searchable( TableDefinition $d, TablePage $page ): bool { $rows = $page->rows; $first = reset( $rows ); return false !== $first && '' !== $d->search_text( $first ); } private static function client( TableDefinition $d, TableQuery $q, TablePage $page ): bool { return 'offset' === $d->paging() && 1 === $q->page && '' === $q->search && null !== $page->total && $page->total <= $q->per_page && self::searchable( $d, $page ); } private static function language( TableDefinition $d ): string { $provider = Providers::current(); if ( 'none' === $provider->id() ) { return ''; } $lang = '' !== $d->language() ? Language::normalize( $d->language() ) : Names::display_language(); foreach ( $provider->languages() as $code ) { if ( Language::normalize( (string) $code ) === $lang ) { return $lang; } } return ''; } private static function strings( TableDefinition $d ): array { return array( 'error' => __( 'The table could not be loaded. Try again.', 'rooster-lms' ), 'loading' => __( 'Loading…', 'rooster-lms' ), /* translators: %s: number of selected rows. */ 'selected' => __( '%s selected', 'rooster-lms' ), 'confirm' => __( 'Confirm', 'rooster-lms' ), 'cancel' => __( 'Cancel', 'rooster-lms' ), 'exporting' => __( 'Preparing the file…', 'rooster-lms' ), 'cleared' => __( 'Selection cleared', 'rooster-lms' ), /* translators: 1: first row number, 2: last row number, 3: number of rows. */ 'showing' => __( 'Showing %1$s–%2$s of %3$s', 'rooster-lms' ), 'none' => __( 'No results', 'rooster-lms' ), 'empty' => $d->empty_text( true ), 'pages' => __( 'Pages', 'rooster-lms' ), 'prev' => __( 'Previous page', 'rooster-lms' ), 'next' => __( 'Next page', 'rooster-lms' ), /* translators: %s: page number. */ 'page' => __( 'Page %s', 'rooster-lms' ), 'asc' => __( ', sorted ascending', 'rooster-lms' ), 'desc' => __( ', sorted descending', 'rooster-lms' ), 'chevron' => Pager::chevron(), ); } private static function toolbar( TableDefinition $d, TableQuery $q, string $uid, array $columns ): string { $end = self::forms( $d, $q, $uid ) . self::tools( $d, $columns, $uid ); if ( Ui::kit_markup() ) { $end = '' !== $end ? '
' . $end . '
' : ''; $all = self::views_nav( $d ) . $end; return '' !== $all ? '
' . $all . '
' : ''; } $end = '' !== $end ? '
' . $end . '
' : ''; $all = self::views_nav( $d ) . $end; return '' !== $all ? '
' . $all . '
' : ''; } private static function views_nav( TableDefinition $d ): string { $views = $d->table_views(); return null === $views ? '' : $views->html(); } private static function view_filter( 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 forms( TableDefinition $d, TableQuery $q, string $uid ): string { $names = TableQuery::arg_names( $d ); $view_key = self::view_filter( $d ); $filters = self::toolbar_filters( $d ); $search = '' !== $d->search_label(); $post = $search && 'post' === $d->search_transport(); $visible = self::toolbar_visible( $d ); $has_form = $visible || count( self::page_sizes( $d ) ) > 1; $html = ''; if ( $post ) { $html .= ''; } if ( ! $has_form ) { return $html; } $base = TableQuery::strip( $d, $d->base_url() ); $action = explode( '?', $base, 2 )[0]; $view = '' !== $view_key ? $q->filter( $view_key ) : ''; $view = is_string( $view ) ? $view : ''; $kit = Ui::kit_markup(); $html .= ''; } private static function toolbar_filters( TableDefinition $d ): array { $view_key = self::view_filter( $d ); return array_values( array_filter( $d->filters(), static fn( Filter $f ): bool => $f->key !== $view_key ) ); } private static function toolbar_visible( TableDefinition $d ): bool { return array() !== self::toolbar_filters( $d ) || ( '' !== $d->search_label() && 'post' !== $d->search_transport() ); } private static function page_sizes( TableDefinition $d ): array { return 'offset' === $d->paging() || 'keyset' === $d->paging() ? array_values( array_unique( array_map( 'intval', $d->per_page_options() ) ) ) : array(); } private static function clear_link( string $url, bool $active ): string { return '' . self::icon( 'x' ) . esc_html__( 'Clear filters', 'rooster-lms' ) . ''; } private static function search_field( TableDefinition $d, TableQuery $q, string $name, string $uid ): string { $id = $uid . '-search'; if ( Ui::kit_markup() ) { return '
' . \Rooster\Admin\Ui::input( $name, $q->search, array( 'id' => $id, 'type' => 'search', 'icon' => 'search', 'placeholder' => $d->search_label(), 'maxlength' => (string) TableQuery::SEARCH_MAX, 'autocomplete' => 'off', 'attrs' => array( 'data-rl-search' => $d->search_transport() ), ) ) . '
'; } return ''; } private static function filter_control( Filter $filter, TableQuery $q, string $name, string $uid ): string { $id = $uid . '-' . sanitize_html_class( $filter->key ); $current = $q->filter( $filter->key ); if ( Filter::TOGGLE === $filter->type ) { $value = (string) array_key_first( array_filter( $filter->options, static fn( $label, $value ): bool => '' !== (string) $value, ARRAY_FILTER_USE_BOTH ) ); if ( Ui::kit_markup() ) { return \Rooster\Admin\Ui::toggle( $name, '' !== checked( $current, $value, false ), array( 'id' => $id, 'value' => $value, 'label' => $filter->label, 'hidden' => false, 'attrs' => array( 'data-rl-filter' => $filter->key ), ) ); } $hint = '' !== $filter->hint ? '' . esc_html( $filter->hint ) . '' : ''; if ( '' !== $hint ) { Assets::enqueue_tip(); } return '' . $hint; } $multi = Filter::MULTI === $filter->type; $needs = '' !== $filter->depends ? $q->filter( $filter->depends ) : 'x'; $off = '' === $needs || array() === $needs; if ( Ui::kit_markup() ) { $options = ''; foreach ( $filter->options as $value => $label ) { $value = (string) $value; $on = $multi ? '' !== $value && in_array( $value, (array) $current, true ) : $value === $current; $options .= ''; } $select = ''; return \Rooster\Admin\Ui::filter( $filter->label, $select, $id, $off ? array( 'tip' => $filter->hint ) : array() ); } $html = ''; } private static function hidden_args( string $base ): string { $query = (string) wp_parse_url( $base, PHP_URL_QUERY ); if ( '' === $query ) { return ''; } $args = array(); wp_parse_str( $query, $args ); $html = ''; foreach ( $args as $name => $value ) { if ( is_scalar( $value ) ) { $html .= ''; } } return $html; } private static function tools( TableDefinition $d, array $columns, string $uid ): string { $hideable = array(); $off = array() !== $d->bulk() ? 1 : 0; foreach ( $columns as $i => $column ) { if ( $column->hideable && '' !== $column->label && ! $column->sr_only ) { $hideable[] = array( 'key' => $column->key, 'label' => $column->label, 'index' => $i + 1 + $off, 'visible' => $column->visible, ); } } $group = self::columns_tool( $uid, $hideable, count( array_filter( $columns, static fn( $c ): bool => '' !== $c->label && ! $c->sr_only ) ) - count( $hideable ) ); $label = __( 'Compact rows', 'rooster-lms' ); $kit = Ui::kit_markup(); if ( $kit ) { $group .= \Rooster\Admin\Ui::button( $label, array( 'icon' => 'rows-3', 'icon_only' => true, 'attrs' => array( 'aria-pressed' => 'false', 'data-rl-density' => '1', 'data-rl-js' => '1', ), ) ); $items = '
' . $group . '
'; } else { $group .= ''; $items = '
' . $group . '
'; } foreach ( $d->exports() as $export ) { if ( ! $export instanceof ExportLink ) { continue; } if ( $kit ) { $items .= ExportLink::URL === $export->kind ? \Rooster\Admin\Ui::button( $export->label, array( 'icon' => 'download', 'href' => $export->target, 'class' => 'rooster-lms-table__export', 'attrs' => array( 'data-rl-export-url' => '1' ) + ( $export->shown ? array( 'data-rl-export-columns' => 'columns' ) : array() ), ) ) : \Rooster\Admin\Ui::button( $export->label, array( 'icon' => 'download', 'class' => 'rooster-lms-table__export', 'attrs' => array( 'data-rl-js' => '1', 'data-rl-export' => $export->target, 'data-rl-format' => $export->format, 'data-rl-map' => (string) wp_json_encode( (object) $export->map ), ), ) ); continue; } if ( ExportLink::URL === $export->kind ) { $items .= 'shown ? ' data-rl-export-columns="columns"' : '' ) . '>' . self::icon( 'download' ) . esc_html( $export->label ) . ''; } else { $items .= ''; } } return '
' . $items . '
'; } public static function columns_tool( string $uid, array $columns, int $fixed = 0 ): string { $menu = ''; foreach ( $columns as $column ) { $menu .= '
  • '; } if ( '' === $menu ) { return ''; } $label = __( 'Columns', 'rooster-lms' ); if ( Ui::kit_markup() ) { $shown = $fixed + count( array_filter( $columns, static fn( array $c ): bool => ! empty( $c['visible'] ) ) ); /* translators: 1: the columns shown, 2: all the columns. */ $words = __( 'Columns %1$s of %2$s', 'rooster-lms' ); return '
    ' . \Rooster\Admin\Ui::button( sprintf( $words, number_format_i18n( $shown ), number_format_i18n( $fixed + count( $columns ) ) ), array( 'icon' => 'columns-3', 'size' => 'sm', 'attrs' => array( 'aria-expanded' => 'false', 'aria-controls' => $uid . '-columns', 'data-rl-columns' => '1', 'data-rl-columns-fixed' => (string) $fixed, 'data-rl-columns-words' => $words, ), ) ) . '
    '; } return '
    ' . '
    '; } private static function icon( string $name ): string { $paths = array( 'search' => '', 'columns' => '', 'rows' => '', 'download' => '', 'x' => '', ); return ''; } private static function footer( TableDefinition $d, TableQuery $q, TablePage $page, string $uid ): string { if ( Ui::kit_markup() ) { $html = '
    ' . esc_html( self::summary( $q, $page ) ) . '
    '; if ( 'offset' === $d->paging() || 'keyset' === $d->paging() ) { $html .= '' . self::pager( $d, $q, $page ) . ''; } $sizes = self::page_sizes( $d ); if ( count( $sizes ) > 1 ) { $id = $uid . '-per-page'; $options = ''; foreach ( $sizes as $size ) { $options .= ''; } $html .= '
    ' . '
    '; if ( ! self::toolbar_visible( $d ) ) { $html .= self::nojs_submit( __( 'Apply', 'rooster-lms' ), $uid . '-filters' ); } } return ''; } $html = '

    ' . esc_html( self::summary( $q, $page ) ) . '

    '; if ( 'offset' === $d->paging() || 'keyset' === $d->paging() ) { $html .= '' . self::pager( $d, $q, $page ) . ''; } $sizes = self::page_sizes( $d ); if ( count( $sizes ) > 1 ) { $id = $uid . '-per-page'; $html .= ''; if ( ! self::toolbar_visible( $d ) ) { $html .= self::nojs_submit( __( 'Apply', 'rooster-lms' ), $uid . '-filters' ); } } return ''; } private static function chips( TableDefinition $d, TableQuery $q, TablePage $page ): string { $chips = $d->chips(); if ( array() === $chips ) { return ''; } $html = ''; foreach ( $chips as $chip ) { $key = (string) ( $chip['key'] ?? '' ); $value = (string) ( $chip['value'] ?? '' ); $on = $q->filter( $key ) === $value; $url = $q->url( $d, array( 'filters' => array( $key => $on ? null : $value ), 'page' => 1, 'after' => '', ) ); $count = $page->counts[ $key ][ $value ] ?? null; $html .= '' . esc_html( (string) ( $chip['label'] ?? $value ) ); if ( null !== $count ) { $html .= ' ' . esc_html( Format::number( (int) $count ) ) . ''; } $html .= ''; } return '

    ' . $html . '

    '; } public static function summary( TableQuery $q, TablePage $page ): string { $n = count( $page->rows ); if ( 0 === $n ) { return 0 === (int) $page->total || $q->page <= 1 ? __( 'No results', 'rooster-lms' ) : ''; } $from = $q->offset() + 1; $to = $q->offset() + $n; if ( null === $page->total ) { /* translators: 1: first row number, 2: last row number. */ return sprintf( __( 'Showing %1$s–%2$s', 'rooster-lms' ), Format::number( $from ), Format::number( $to ) ); } /* translators: 1: first row number, 2: last row number, 3: number of rows. */ return sprintf( __( 'Showing %1$s–%2$s of %3$s', 'rooster-lms' ), Format::number( $from ), Format::number( $to ), Format::number( $page->total ) ); } private static function pages( TableQuery $q, TablePage $page ): int { return null === $page->total ? max( 1, $q->page + ( $page->more ? 1 : 0 ) ) : max( 1, (int) ceil( $page->total / max( 1, $q->per_page ) ) ); } private static function table_attrs( TableDefinition $d, array $columns ): string { $off = array() !== $d->bulk() ? 1 : 0; $num = array(); $center = array(); $hide = array(); foreach ( $columns as $i => $column ) { $n = $i + 1 + $off; if ( 'end' === $column->align ) { $num[] = $n; } elseif ( 'center' === $column->align ) { $center[] = $n; } if ( ! $column->visible ) { $hide[] = $n; } } $attrs = array( 'class' => trim( 'rooster-lms-table ' . $d->table_class() ) ); if ( array() !== $num ) { $attrs['data-rl-num'] = implode( ' ', $num ); } if ( array() !== $center ) { $attrs['data-rl-center'] = implode( ' ', $center ); } $attrs['data-rl-hide'] = implode( ' ', $hide ); return self::attrs( $attrs ); } private static function head( TableDefinition $d, TableQuery $q, array $columns ): string { $html = ''; if ( array() !== $d->bulk() ) { $html .= '' . self::bulk_bar( $d->bulk() ) . ''; } foreach ( $columns as $column ) { if ( ! $column->sortable ) { $html .= self::plain_head( $column ); continue; } $current = $q->orderby === $column->key; $sort = $current ? ( 'asc' === $q->order ? 'ascending' : 'descending' ) : 'none'; $next = $current && 'asc' === $q->order ? 'desc' : 'asc'; $url = $q->url( $d, array( 'orderby' => $column->key, 'order' => $next, 'page' => 1, 'after' => '', ) ); $sr = ''; if ( $current ) { $sr = '' . esc_html( 'asc' === $q->order ? __( ', sorted ascending', 'rooster-lms' ) : __( ', sorted descending', 'rooster-lms' ) ) . ''; } $label = $column->sr_only ? '' . esc_html( $column->label ) . '' : esc_html( $column->label ); if ( Ui::kit_markup() ) { $html .= '' . $label . $sr . self::sort_chevron() . ''; continue; } $html .= '' . $label . $sr . ''; } return $html . ''; } private static function plain_head( Column $column ): string { $label = $column->sr_only ? '' . esc_html( $column->label ) . '' : esc_html( $column->label ); if ( '' !== $column->html ) { $label = '' . esc_html( $column->label ) . ''; } return 'data_column ? ' data-column="' . esc_attr( $column->key ) . '"' : '' ) . '>' . $label . ''; } private static function th_class(): string { return Ui::kit_markup() ? ' class="rooster-admin-table__th"' : ''; } public static function sort_chevron(): string { return ''; } private static function body( TableDefinition $d, TableQuery $q, TablePage $page, array $columns ): string { if ( array() === $page->rows ) { $span = count( $columns ) + ( array() !== $d->bulk() ? 1 : 0 ); return '' . esc_html( $d->empty_text( $q->filtered() ) ) . ''; } $html = ''; foreach ( $page->rows as $row ) { $html .= $d->row( $row ); } return $html; } private static function pager( TableDefinition $d, TableQuery $q, TablePage $page ): string { $labels = $d->labels(); if ( 'keyset' === $d->paging() ) { $first = '' !== $q->after ? $q->url( $d, array( 'after' => '', 'page' => 1, ) ) : ''; $more = $page->more && '' !== $page->after ? $q->url( $d, array( 'after' => $page->after, 'page' => $q->page + 1, ) ) : ''; return Pager::keyset( $first, $more, $labels['first'] ?? __( 'First page', 'rooster-lms' ), $labels['more'] ?? __( 'Next page', 'rooster-lms' ) ); } if ( 'offset' !== $d->paging() ) { return ''; } if ( null === $page->total ) { return Pager::steps( $q->page > 1 ? $q->url( $d, array( 'page' => $q->page - 1 ) ) : '', $page->more ? $q->url( $d, array( 'page' => $q->page + 1 ) ) : '' ); } return Pager::offset( $q->page, self::pages( $q, $page ), static fn( int $n ): string => $q->url( $d, array( 'page' => $n ) ) ); } private static function bulk_bar( array $actions ): string { /* translators: %s: number of selected rows. */ $count = sprintf( __( '%s selected', 'rooster-lms' ), Format::number( 0 ) ); $html = ''; } return $html . ''; } public static function kit_button( string $label, string $variant, array $attrs = array(), string $type = 'button' ): string { $variant = array( 'secondary' => 'outline', 'dim' => 'ghost', )[ $variant ] ?? $variant; $class = 'rooster-admin-button' . ( in_array( $variant, array( 'primary', 'ghost', 'destructive', 'mono' ), true ) ? ' rooster-admin-button--' . $variant : '' ) . ' rooster-admin-button--sm'; return ' $class ) + $attrs + array( 'type' => 'submit' === $type ? 'submit' : 'button' ) ) . '>' . esc_html( $label ) . ''; } private static function attrs( array $attrs ): string { $out = ''; foreach ( $attrs as $name => $value ) { if ( false === $value ) { continue; } $out .= true === $value ? ' ' . esc_attr( $name ) : ' ' . esc_attr( $name ) . '="' . esc_attr( (string) $value ) . '"'; } return $out; } }